Преглед на файлове

[frontend] Add cancel related improvements to CancellablePromise

Johan Ahlen преди 5 години
родител
ревизия
678f46013d
променени са 1 файла, в които са добавени 39 реда и са изтрити 7 реда
  1. 39 7
      desktop/core/src/desktop/js/api/cancellablePromise.ts

+ 39 - 7
desktop/core/src/desktop/js/api/cancellablePromise.ts

@@ -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 {
-    if (this.onCancel) {
-      this.onCancel();
+  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);
+    });
+  }
 }