From a5ba28b2ff5abc980edb754feb3fcba057ac8d0a Mon Sep 17 00:00:00 2001 From: dineug Date: Thu, 24 Aug 2023 20:48:44 +0900 Subject: [PATCH] fix: operator cancel --- .github/workflows/ci.yml | 1 + packages/go/README.md | 25 +++++++++++-------------- packages/go/package.json | 2 +- packages/go/src/go.ts | 19 ++++++------------- packages/go/src/is-type.ts | 11 ----------- packages/go/src/operators/cancel.ts | 19 +++++++++++++++++-- packages/go/src/operators/debounce.ts | 4 ++-- packages/go/src/operators/delay.ts | 2 +- packages/go/src/operators/take.ts | 10 +++++----- packages/go/src/operators/takeLatest.ts | 4 ++-- packages/go/src/operators/throttle.ts | 2 +- 11 files changed, 47 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27def75..17fbac3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,5 +15,6 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 + cache: 'pnpm' - run: pnpm install - run: pnpm build diff --git a/packages/go/README.md b/packages/go/README.md index b331940..e14d0a7 100644 --- a/packages/go/README.md +++ b/packages/go/README.md @@ -90,14 +90,10 @@ go(foo); #### interface ```ts -type PromiseWithCancel = Promise & { - cancel(): PromiseWithCancel; -}; - function go( callback: F, ...args: Parameters -): PromiseWithCancel>; +): Promise>; ``` #### callback @@ -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((resolve, reject) => reject(CANCEL))); }; ``` @@ -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); } }); ``` @@ -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 @@ -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; @@ -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) diff --git a/packages/go/package.json b/packages/go/package.json index e7a0870..1576ed7 100644 --- a/packages/go/package.json +++ b/packages/go/package.json @@ -38,7 +38,7 @@ "author": "SeungHwan-Lee ", "license": "MIT", "scripts": { - "dev": "vite", + "dev": "vite dev", "build": "vite build" }, "devDependencies": { diff --git a/packages/go/src/go.ts b/packages/go/src/go.ts index 5ebddcc..12b619e 100644 --- a/packages/go/src/go.ts +++ b/packages/go/src/go.ts @@ -7,6 +7,7 @@ import { } from '@/is-type'; import { type AnyCallback, + attachCancel, CANCEL, cancel, isCancel, @@ -17,14 +18,7 @@ export type CompositionGenerator = | Generator> | AsyncGenerator>; -export type PromiseWithCancel = Promise & { - cancel(): PromiseWithCancel; -}; - -export type CompositionPromise = - | Promise - | PromiseLike - | PromiseWithCancel; +export type CompositionPromise = Promise | PromiseLike; export type CoroutineCreator = ( ...args: any[] @@ -48,7 +42,7 @@ type GoReturnType< export function go( callback: F, ...args: Parameters -): PromiseWithCancel> { +): Promise> { let canceled = false; let cancelAndReject: AnyCallback | null = null; @@ -99,13 +93,12 @@ export function go( } reject(error); } - }) as PromiseWithCancel; + }) as Promise>; - promise.cancel = () => { + attachCancel(promise, () => { canceled = true; cancelAndReject?.(); - return promise; - }; + }); return promise; } diff --git a/packages/go/src/is-type.ts b/packages/go/src/is-type.ts index 26602bf..c1d588c 100644 --- a/packages/go/src/is-type.ts +++ b/packages/go/src/is-type.ts @@ -1,5 +1,3 @@ -import type { PromiseWithCancel } from '@/go'; - type typeofKey = | 'bigint' | 'boolean' @@ -46,15 +44,6 @@ export const isPromise = (value: any): value is Promise => isFunction(value.catch) && isFunction(value.finally); -export const isPromiseWithCancel = ( - value: any -): value is PromiseWithCancel => - isObject(value) && - isFunction(value.then) && - isFunction(value.catch) && - isFunction(value.finally) && - isFunction(value.cancel); - export const isIterator = ( value: any ): value is Iterator | AsyncIterator => diff --git a/packages/go/src/operators/cancel.ts b/packages/go/src/operators/cancel.ts index 2f3cd77..e93e4eb 100644 --- a/packages/go/src/operators/cancel.ts +++ b/packages/go/src/operators/cancel.ts @@ -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 = ( + promise: Promise, + cancel: () => void +): Promise => { + Reflect.set(promise, ATTACH_CANCEL, cancel); + return promise; +}; export const isCancel = (value: any): value is typeof CANCEL => value === CANCEL; export const cancel = (promise?: CompositionPromise) => { - isPromiseWithCancel(promise) && promise.cancel(); + if (isObject(promise)) { + const cancel = Reflect.get(promise, ATTACH_CANCEL); + cancel?.(); + } + return go(() => new Promise((resolve, reject) => reject(CANCEL))); }; diff --git a/packages/go/src/operators/debounce.ts b/packages/go/src/operators/debounce.ts index 16f2509..5a003d6 100644 --- a/packages/go/src/operators/debounce.ts +++ b/packages/go/src/operators/debounce.ts @@ -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); } }); diff --git a/packages/go/src/operators/delay.ts b/packages/go/src/operators/delay.ts index e6566fd..1d4544d 100644 --- a/packages/go/src/operators/delay.ts +++ b/packages/go/src/operators/delay.ts @@ -1,4 +1,4 @@ import { go } from '@/go'; export const delay = (ms: number) => - go(() => new Promise(resolve => window.setTimeout(resolve, ms))); + go(() => new Promise(resolve => setTimeout(resolve, ms))); diff --git a/packages/go/src/operators/take.ts b/packages/go/src/operators/take.ts index e57054f..4b67cea 100644 --- a/packages/go/src/operators/take.ts +++ b/packages/go/src/operators/take.ts @@ -1,5 +1,6 @@ import { Channel } from '@/channel'; -import { go, type PromiseWithCancel } from '@/go'; +import { go } from '@/go'; +import { attachCancel } from '@/operators/cancel'; export const take = (channel: Channel) => go(function* () { @@ -7,12 +8,11 @@ export const take = (channel: Channel) => const promise = new Promise((resolve, reject) => { drop = channel.take(resolve, reject); - }) as PromiseWithCancel; + }); - promise.cancel = () => { + attachCancel(promise, () => { drop(); - return promise; - }; + }); const value: T = yield promise; return value; diff --git a/packages/go/src/operators/takeLatest.ts b/packages/go/src/operators/takeLatest.ts index ce50ee9..a57ade2 100644 --- a/packages/go/src/operators/takeLatest.ts +++ b/packages/go/src/operators/takeLatest.ts @@ -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'; @@ -11,7 +11,7 @@ export const takeLatest = < callback: F ) => go(function* () { - let lastTask: PromiseWithCancel | undefined; + let lastTask: Promise | undefined; while (true) { const value: any = yield take(channel); diff --git a/packages/go/src/operators/throttle.ts b/packages/go/src/operators/throttle.ts index 426dc77..4dae55e 100644 --- a/packages/go/src/operators/throttle.ts +++ b/packages/go/src/operators/throttle.ts @@ -41,7 +41,7 @@ export const throttle = < go(callback, value); } - timerId = window.setTimeout(() => { + timerId = setTimeout(() => { if ( options.trailing && (!options.leading || leadingValue !== trailingValue)