feat: 재사용가능한 signal

This commit is contained in:
2024-03-09 07:04:25 +00:00
parent 66c8261438
commit 3b460b5f04
2 changed files with 103 additions and 0 deletions
+1
View File
@@ -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"
+102
View File
@@ -0,0 +1,102 @@
type RejectType = {
type: 'reject';
reason: string | Error;
};
type ResolveType<T> = {
type: 'resolve';
value?: T;
};
type Response<T> = ResolveType<T> | RejectType | {
type: 'timeout' | 'abort';
};
const enum TimeoutState {
notYetWait = 0,
waiting = 1,
done = 2,
timeout = 3,
}''
/**
* 재사용 가능한 Signal 클래스
*/
export class Signal<T = undefined> {
private resolved: boolean = false;
private timeoutState: TimeoutState = TimeoutState.notYetWait;
private _promise!: Promise<Response<T>>;
private _resolve!: (value: Response<T>) => void;
private timeoutID?: ReturnType<typeof setTimeout>;
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<Response<T>>{
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<void> {
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<void> {
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});
}
}