From 3b460b5f043f597ddc37a7c0133375f2a043182b Mon Sep 17 00:00:00 2001 From: Hide_D Date: Sat, 9 Mar 2024 07:04:25 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=AC=EC=82=AC=EC=9A=A9=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=9C=20signal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @sammo/util/src/index.ts | 1 + @sammo/util/src/signal.ts | 102 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 @sammo/util/src/signal.ts diff --git a/@sammo/util/src/index.ts b/@sammo/util/src/index.ts index 4595043..2c2c730 100644 --- a/@sammo/util/src/index.ts +++ b/@sammo/util/src/index.ts @@ -5,6 +5,7 @@ export * from "./unwrap.js" export * from "./must.js" export * from "./types.js" export * from "./web.js" +export * from "./signal.js" export * from "./strongType.js" diff --git a/@sammo/util/src/signal.ts b/@sammo/util/src/signal.ts new file mode 100644 index 0000000..15bbc0c --- /dev/null +++ b/@sammo/util/src/signal.ts @@ -0,0 +1,102 @@ + + +type RejectType = { + type: 'reject'; + reason: string | Error; +}; + +type ResolveType = { + type: 'resolve'; + value?: T; +}; + +type Response = ResolveType | RejectType | { + type: 'timeout' | 'abort'; +}; + +const enum TimeoutState { + notYetWait = 0, + waiting = 1, + done = 2, + timeout = 3, +}'' + +/** + * 재사용 가능한 Signal 클래스 + */ +export class Signal { + private resolved: boolean = false; + private timeoutState: TimeoutState = TimeoutState.notYetWait; + + private _promise!: Promise>; + private _resolve!: (value: Response) => void; + private timeoutID?: ReturnType; + + constructor(public readonly timeoutMs?: number) { + this.reset(); + } + + public reset(): void { + if(this.timeoutID){ + clearTimeout(this.timeoutID); + this.timeoutID = undefined; + } + + this.resolved = false; + this.timeoutState = TimeoutState.notYetWait; + this._promise = new Promise((resolve) => { + this._resolve = resolve; + }); + + if(this.timeoutMs){ + this.timeoutID = setTimeout(() => { + this._timeout(); + }, this.timeoutMs); + } + } + + private _timeout(){ + if(this.timeoutState === TimeoutState.waiting){ + this.resolved = true; + this._resolve({type: 'timeout'}); + } + this.timeoutState = TimeoutState.timeout; + } + + public async wait(): Promise>{ + if(this.timeoutState === TimeoutState.timeout){ + this.reset(); + return {type: 'timeout'}; + } + this.timeoutState = TimeoutState.waiting; + const result = await this._promise; + this.reset(); + return result; + } + + public async abort(): Promise { + if(this.resolved){ + return; + } + this.resolved = true; + this.timeoutState = TimeoutState.done; + if(this.timeoutID){ + clearTimeout(this.timeoutID); + this.timeoutID = undefined; + } + this._resolve({type: 'abort'}); + } + + public async notify(value?: T): Promise { + if(this.resolved){ + return; + } + this.resolved = true; + this.timeoutState = TimeoutState.done; + if(this.timeoutID){ + clearTimeout(this.timeoutID); + this.timeoutID = undefined; + } + this._resolve({type: 'resolve', value}); + } +} \ No newline at end of file