Files
core_ng/@sammo/util/src/signal.ts
T
2024-03-09 16:31:35 +00:00

102 lines
2.4 KiB
TypeScript

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 abort(): 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 notify(value?: T): 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});
}
}