Files
node-template-express/public/js-source/src/utils/resolvable.ts
Sebastian Seedorf b79c2f96cd Added frontend tests
2020-11-17 00:06:10 +01:00

90 lines
2.1 KiB
TypeScript

enum ResolvableState {
WAITING,
PENDING,
ERROR,
DONE
}
class FetchOnce<T, U extends Array<unknown>> {
protected data: T|undefined;
protected error: unknown|undefined;
protected state: ResolvableState = ResolvableState.WAITING;
protected pendings: [(res: Promise<T>|T) => void, (reason: unknown) => void][] = [];
constructor(protected fetchMethod?: (...args: U) => Promise<T>) { }
public reset(): void {
this.data = undefined;
this.error = undefined;
this.state = ResolvableState.WAITING;
}
public resolve(...args: U): Promise<T> {
return new Promise((resolve, reject) => {
switch (this.state) {
case ResolvableState.WAITING:
this.state = ResolvableState.PENDING;
this.pendings.push([resolve, reject]);
if (this.fetchMethod) this.parsePromise(this.fetchMethod(...args));
break;
case ResolvableState.PENDING:
this.pendings.push([resolve, reject]);
break;
case ResolvableState.DONE:
resolve(this.data);
break;
case ResolvableState.ERROR:
reject(this.error);
break;
}
});
}
protected isFinished(): boolean {
return this.state === ResolvableState.DONE || this.state === ResolvableState.ERROR;
}
protected parsePromise(promise: Promise<T>): void {
promise.then((data) => {
this.data = data;
this.state = ResolvableState.DONE;
this.pendings.forEach(pending => pending[0](data));
}).catch(err => {
this.error = err;
this.state = ResolvableState.ERROR;
this.pendings.forEach(pending => pending[1](err));
});
}
}
export class Resolvable<T, U extends Array<unknown>> extends FetchOnce<T, U> {
constructor(fetchMethod: (...args: U) => Promise<T>) {
super(fetchMethod);
}
}
export class WaitForSync<T> extends FetchOnce<T, never> {
protected state: ResolvableState = ResolvableState.PENDING;
constructor() {
super(undefined);
}
public setData(data: T): void {
if (!this.isFinished()) {
this.parsePromise((async () => data)());
}
}
public setError(error: unknown): void {
if (!this.isFinished()) {
this.parsePromise((async () => { throw error; })());
}
}
public reset(): void {
super.reset();
this.state = ResolvableState.PENDING;
}
}