feat: 재사용가능한 signal
This commit is contained in:
@@ -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"
|
||||
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user