Skip to content

Commit

Permalink
feat(defer): implement cancellable callback (#3916)
Browse files Browse the repository at this point in the history
  • Loading branch information
samouss authored and Haroenv committed Oct 23, 2019
1 parent dbbda0f commit 43a0bf8
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 2 deletions.
57 changes: 57 additions & 0 deletions src/lib/utils/__tests__/defer.ts
Expand Up @@ -51,4 +51,61 @@ describe('defer', () => {

expect(fn).toHaveBeenCalledTimes(2);
});

it('cancels the deferred function', async () => {
const fn = jest.fn();
const deferred = defer(fn);

deferred();

expect(fn).toHaveBeenCalledTimes(0);

deferred.cancel();

expect(fn).toHaveBeenCalledTimes(0);

await Promise.resolve();

expect(fn).toHaveBeenCalledTimes(0);
});

it('cancels only the current deferred function', async () => {
const fn = jest.fn();
const deferred = defer(fn);

deferred();

expect(fn).toHaveBeenCalledTimes(0);

deferred.cancel();

expect(fn).toHaveBeenCalledTimes(0);

await Promise.resolve();

expect(fn).toHaveBeenCalledTimes(0);

deferred();

await Promise.resolve();

expect(fn).toHaveBeenCalledTimes(1);
});

it('cancels only the running deferred function', async () => {
const fn = jest.fn();
const deferred = defer(fn);

deferred.cancel();

expect(fn).toHaveBeenCalledTimes(0);

deferred();

expect(fn).toHaveBeenCalledTimes(0);

await Promise.resolve();

expect(fn).toHaveBeenCalledTimes(1);
});
});
23 changes: 21 additions & 2 deletions src/lib/utils/defer.ts
@@ -1,19 +1,38 @@
const nextMicroTask = Promise.resolve();

type Callback = (...args: any[]) => void;
type Cancellable = Callback & {
cancel(): void;
};

const defer = (callback: Callback): Callback => {
const defer = (callback: Callback): Cancellable => {
let progress: Promise<void> | null = null;
return (...args) => {
let cancelled = false;

const fn: Cancellable = (...args) => {
if (progress !== null) {
return;
}

progress = nextMicroTask.then(() => {
if (cancelled) {
progress = null;
cancelled = false;
return;
}

callback(...args);
progress = null;
});
};

fn.cancel = () => {
if (progress !== null) {
cancelled = true;
}
};

return fn;
};

export default defer;

0 comments on commit 43a0bf8

Please sign in to comment.