[frontend] Add cancel related improvements to CancellablePromise
@@ -20,24 +20,56 @@ export interface Cancellable {
export class CancellablePromise<T> extends Promise<T> implements Cancellable {
private readonly onCancel?: () => void;
+ private readonly rejectHandler?: (reason?: unknown) => void;
+ private cancelPrevented?: boolean;
+ cancelled?: boolean;
constructor(
handlers: (
resolve: (value?: T | PromiseLike<T>) => void,
reject: (reason?: unknown) => void,
- onCancel?: (cancelHandler: () => void) => void
+ onCancel: (cancelHandler: () => void) => void
) => void
) {
let onCancel: undefined | (() => void) = undefined;
- super((resolve, reject) =>
- handlers(resolve, reject, (cancelHandler: () => void) => (onCancel = cancelHandler))
- );
+ let rejectHandler: undefined | ((reason?: unknown) => void) = undefined;
+ super((resolve, reject) => {
+ rejectHandler = reject;
+ return handlers(resolve, reject, (cancelHandler: () => void) => (onCancel = cancelHandler));
+ });
+ this.rejectHandler = rejectHandler;
this.onCancel = onCancel;
}
- cancel(): void {
+ async cancel(): Promise<void> {
+ if (!this.cancelPrevented) {
+ const testSymbol = Symbol();
+ const firstToFinish = await Promise.race([this, Promise.resolve(testSymbol)]);
+ if (firstToFinish === testSymbol) {
if (this.onCancel) {
this.onCancel();
}
+ if (this.rejectHandler) {
+ this.rejectHandler();
+ }
+ this.cancelled = true;
+ }
+ }
+ }
+
+ preventCancel(): void {
+ this.cancelPrevented = true;
+ }
+
+ static reject<T = unknown>(reason?: unknown): CancellablePromise<T> {
+ return new CancellablePromise<T>((resolve, reject) => {
+ reject(reason);
+ });
+ }
+
+ static resolve<T = unknown>(value?: T | PromiseLike<T>): CancellablePromise<T> {
+ return new CancellablePromise<T>(resolve => {
+ resolve(value);
+ });
}
}
