Skip to content

Commit

Permalink
fix: operator cancel
Browse files Browse the repository at this point in the history
  • Loading branch information
dineug committed Aug 24, 2023
1 parent 8c63b5b commit a5ba28b
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 52 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'pnpm'
- run: pnpm install
- run: pnpm build
25 changes: 11 additions & 14 deletions packages/go/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,10 @@ go(foo);
#### interface

```ts
type PromiseWithCancel<T = any> = Promise<T> & {
cancel(): PromiseWithCancel<T>;
};

function go<F extends AnyCallback>(
callback: F,
...args: Parameters<F>
): PromiseWithCancel<GoReturnType<F>>;
): Promise<GoReturnType<F>>;
```

#### callback
Expand Down Expand Up @@ -198,7 +194,10 @@ go(function* () {

```js
const cancel = promise => {
isPromiseWithCancel(promise) && promise.cancel();
if (isObject(promise)) {
const cancel = Reflect.get(promise, ATTACH_CANCEL);
cancel?.();
}
return go(() => new Promise<void>((resolve, reject) => reject(CANCEL)));
};
```
Expand All @@ -221,8 +220,8 @@ const debounce = (channel, callback, ms) =>
while (true) {
const value = yield take(channel);

window.clearTimeout(timerId);
timerId = window.setTimeout(go, ms, callback, value);
clearTimeout(timerId);
timerId = setTimeout(go, ms, callback, value);
}
});
```
Expand All @@ -240,8 +239,7 @@ go(function* () {
#### low-level operator
```js
const delay = ms =>
go(() => new Promise(resolve => window.setTimeout(resolve, ms)));
const delay = ms => go(() => new Promise(resolve => setTimeout(resolve, ms)));
```
### flush
Expand Down Expand Up @@ -359,10 +357,9 @@ const take = channel =>
drop = channel.take(resolve, reject);
});

promise.cancel = () => {
attachCancel(promise, () => {
drop();
return promise;
};
});

const value = yield promise;
return value;
Expand Down Expand Up @@ -481,7 +478,7 @@ const throttle = (channel, callback, ms, config) =>
go(callback, value);
}

timerId = window.setTimeout(() => {
timerId = setTimeout(() => {
if (
options.trailing &&
(!options.leading || leadingValue !== trailingValue)
Expand Down
2 changes: 1 addition & 1 deletion packages/go/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"author": "SeungHwan-Lee <dineug2@gmail.com>",
"license": "MIT",
"scripts": {
"dev": "vite",
"dev": "vite dev",
"build": "vite build"
},
"devDependencies": {
Expand Down
19 changes: 6 additions & 13 deletions packages/go/src/go.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@/is-type';
import {
type AnyCallback,
attachCancel,
CANCEL,
cancel,
isCancel,
Expand All @@ -17,14 +18,7 @@ export type CompositionGenerator<T> =
| Generator<T | CompositionGenerator<T>>
| AsyncGenerator<T | CompositionGenerator<T>>;

export type PromiseWithCancel<T = any> = Promise<T> & {
cancel(): PromiseWithCancel<T>;
};

export type CompositionPromise<T = any> =
| Promise<T>
| PromiseLike<T>
| PromiseWithCancel<T>;
export type CompositionPromise<T = any> = Promise<T> | PromiseLike<T>;

export type CoroutineCreator = (
...args: any[]
Expand All @@ -48,7 +42,7 @@ type GoReturnType<
export function go<F extends AnyCallback>(
callback: F,
...args: Parameters<F>
): PromiseWithCancel<GoReturnType<F>> {
): Promise<GoReturnType<F>> {
let canceled = false;
let cancelAndReject: AnyCallback | null = null;

Expand Down Expand Up @@ -99,13 +93,12 @@ export function go<F extends AnyCallback>(
}
reject(error);
}
}) as PromiseWithCancel;
}) as Promise<GoReturnType<F>>;

promise.cancel = () => {
attachCancel(promise, () => {
canceled = true;
cancelAndReject?.();
return promise;
};
});

return promise;
}
Expand Down
11 changes: 0 additions & 11 deletions packages/go/src/is-type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { PromiseWithCancel } from '@/go';

type typeofKey =
| 'bigint'
| 'boolean'
Expand Down Expand Up @@ -46,15 +44,6 @@ export const isPromise = (value: any): value is Promise<any> =>
isFunction(value.catch) &&
isFunction(value.finally);

export const isPromiseWithCancel = (
value: any
): value is PromiseWithCancel<any> =>
isObject(value) &&
isFunction(value.then) &&
isFunction(value.catch) &&
isFunction(value.finally) &&
isFunction(value.cancel);

export const isIterator = (
value: any
): value is Iterator<any> | AsyncIterator<any> =>
Expand Down
19 changes: 17 additions & 2 deletions packages/go/src/operators/cancel.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import { type CompositionPromise, go } from '@/go';
import { isPromiseWithCancel } from '@/is-type';
import { isObject } from '@/is-type';

export const CANCEL = Symbol.for('https://github.com/dineug/go.git#cancel');
export const ATTACH_CANCEL = Symbol.for(
'https://github.com/dineug/go.git#attachCancel'
);

export const attachCancel = <T>(
promise: Promise<T>,
cancel: () => void
): Promise<T> => {
Reflect.set(promise, ATTACH_CANCEL, cancel);
return promise;
};

export const isCancel = (value: any): value is typeof CANCEL =>
value === CANCEL;

export const cancel = <T>(promise?: CompositionPromise<T>) => {
isPromiseWithCancel(promise) && promise.cancel();
if (isObject<object>(promise)) {
const cancel = Reflect.get(promise, ATTACH_CANCEL);
cancel?.();
}

return go(() => new Promise<void>((resolve, reject) => reject(CANCEL)));
};
4 changes: 2 additions & 2 deletions packages/go/src/operators/debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const debounce = <
while (true) {
const value: any = yield take(channel);

window.clearTimeout(timerId);
timerId = window.setTimeout(go, ms, callback, value);
clearTimeout(timerId);
timerId = setTimeout(go, ms, callback, value);
}
});
2 changes: 1 addition & 1 deletion packages/go/src/operators/delay.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { go } from '@/go';

export const delay = (ms: number) =>
go(() => new Promise<void>(resolve => window.setTimeout(resolve, ms)));
go(() => new Promise<void>(resolve => setTimeout(resolve, ms)));
10 changes: 5 additions & 5 deletions packages/go/src/operators/take.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Channel } from '@/channel';
import { go, type PromiseWithCancel } from '@/go';
import { go } from '@/go';
import { attachCancel } from '@/operators/cancel';

export const take = <T = any>(channel: Channel<T>) =>
go(function* () {
let drop = () => false;

const promise = new Promise<T>((resolve, reject) => {
drop = channel.take(resolve, reject);
}) as PromiseWithCancel<T>;
});

promise.cancel = () => {
attachCancel(promise, () => {
drop();
return promise;
};
});

const value: T = yield promise;
return value;
Expand Down
4 changes: 2 additions & 2 deletions packages/go/src/operators/takeLatest.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Channel } from '@/channel';
import { go, type PromiseWithCancel } from '@/go';
import { go } from '@/go';
import { cancel } from '@/operators/cancel';
import { take } from '@/operators/take';

Expand All @@ -11,7 +11,7 @@ export const takeLatest = <
callback: F
) =>
go(function* () {
let lastTask: PromiseWithCancel | undefined;
let lastTask: Promise<any> | undefined;

while (true) {
const value: any = yield take(channel);
Expand Down
2 changes: 1 addition & 1 deletion packages/go/src/operators/throttle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const throttle = <
go(callback, value);
}

timerId = window.setTimeout(() => {
timerId = setTimeout(() => {
if (
options.trailing &&
(!options.leading || leadingValue !== trailingValue)
Expand Down

0 comments on commit a5ba28b

Please sign in to comment.