feat: 재사용가능한 signal
This commit is contained in:
@@ -5,6 +5,7 @@ export * from "./unwrap.js"
|
|||||||
export * from "./must.js"
|
export * from "./must.js"
|
||||||
export * from "./types.js"
|
export * from "./types.js"
|
||||||
export * from "./web.js"
|
export * from "./web.js"
|
||||||
|
export * from "./signal.js"
|
||||||
|
|
||||||
export * from "./strongType.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