UNPKG

@legumeinfo/web-components

Version:

Web Components for the Legume Information System and other AgBio databases

111 lines 3.87 kB
/** * A controller that allows Promises to be cancelled. * * Note that all Promises made cancellable with this controller are cancelled * with the same AbortSignal. Multiple instances of the controller should be * used if multiple signals are desired. */ export class LisCancelPromiseController { /** * @param host - The component that's using the controller. */ constructor(host) { /** @ignore */ this._listeners = []; (this.host = host).addController(this); // members ignored because they're not definitely assigned in the constructor this._initialize(); } /** @ignore */ hostConnected() { this._addEventListener(); } /** @ignore */ hostDisconnected() { this.abortSignal.removeEventListener('abort', this._aborted.bind(this)); } /** * Makes a Promise cancellable by racing it against a Promise that only * cancels. * * @typeParam T - The type of the value the {@link !Promise | `Promise`} to be * wrapped resolves to. * * @param promise - The promise to wrap. * * @returns A new {@link !Promise | `Promise`} that will resolve if the * `promise` parameter resolves or reject with the `'abort'` * {@link !Event | `Event`} raised by the * {@link LisCancelPromiseController.abortSignal | `abortSignal`} if the * promise is cancelled. */ wrapPromise(promise) { // create a Promise race that will reject when the abort signal emits const cancelState = this._cancelState; cancelState.wrapCount += 1; return Promise.race([promise, cancelState.promise]); } /** * Adds a listener to the abort event. * * @param listener - The listener to subscribe to cancel events. */ addListener(listener) { // each listener is called in the scope of the host this._listeners.push(listener.bind(this.host)); } /** * Cancels all Promises that have been made since the last cancel. */ cancel() { this._abortController.abort(); } /** @ignore */ _addEventListener() { this.abortSignal.addEventListener('abort', this._aborted.bind(this), { once: true, }); } /** @ignore */ // creates the Promise that only cancels _initialize() { // initialize the AbortController and the AbortSignal variable this._abortController = new AbortController(); this.abortSignal = this._abortController.signal; // add the abort event listener this._addEventListener(); // intialize the cancel state const cancelState = { abortSignal: this.abortSignal, wrapCount: 0, }; cancelState.promise = new Promise((_, reject) => { // cancel the promise when the abort signal emits cancelState.abortSignal.addEventListener('abort', (event) => reject(event), { once: true }); }) // the default error handler .catch((error) => { // only throw an error if a Promise downstream can catch it if (cancelState.wrapCount > 0) { throw error; } }); this._cancelState = cancelState; } /** @ignore */ // calls all listeners of the aobrt event _aborted(event) { // create a new cancel only promise this._initialize(); // redraw the host this.host.requestUpdate(); // wait for the redraw to complete in case any listeners rely on state from the template this.host.updateComplete.then(() => { // call each listener this._listeners.forEach((listener) => { listener(event); }); }); } } //# sourceMappingURL=lis-cancel-promise-controller.js.map