Compare commits
3 Commits
visdif-err
...
abortable-
Author | SHA1 | Date | |
---|---|---|---|
1c1e4c7c01 | |||
73ac08c0cd | |||
7ff637a1ff |
@ -380,19 +380,46 @@ export function assertSignal(signal: AbortSignal) {
|
||||
* Take a signal and promise, and returns a promise that rejects with an AbortError if the abort is
|
||||
* signalled, otherwise resolves with the promise.
|
||||
*/
|
||||
export async function abortable<T>(
|
||||
export function abortable<T>(
|
||||
signal: AbortSignal,
|
||||
promise: Promise<T>,
|
||||
): Promise<T> {
|
||||
assertSignal(signal);
|
||||
return Promise.race([
|
||||
promise,
|
||||
return abortableFunc(signal, () => promise);
|
||||
}
|
||||
|
||||
type SetAbortArg = (() => void) | undefined;
|
||||
type AbortableCallback<T> = (
|
||||
setAbort: (abortCallback: SetAbortArg) => void,
|
||||
) => Promise<T>;
|
||||
|
||||
/**
|
||||
* A helper to create abortable things.
|
||||
*
|
||||
* @param signal Signal to abort the task
|
||||
* @param callback The task
|
||||
*/
|
||||
export async function abortableFunc<T>(
|
||||
signal: AbortSignal | undefined,
|
||||
callback: AbortableCallback<T>,
|
||||
): Promise<T> {
|
||||
if (signal) assertSignal(signal);
|
||||
let onAbort: (() => void) | undefined;
|
||||
let listener: () => void;
|
||||
const setOnAbort = (abortCallback: SetAbortArg) => {
|
||||
onAbort = abortCallback;
|
||||
};
|
||||
const promise = callback(setOnAbort);
|
||||
|
||||
return Promise.race<T>([
|
||||
new Promise<T>((_, reject) => {
|
||||
signal.addEventListener('abort', () =>
|
||||
reject(new DOMException('AbortError', 'AbortError')),
|
||||
);
|
||||
listener = () => {
|
||||
onAbort?.();
|
||||
reject(new DOMException('AbortError', 'AbortError'));
|
||||
};
|
||||
signal?.addEventListener('abort', listener);
|
||||
}),
|
||||
]);
|
||||
promise,
|
||||
]).finally(() => signal?.removeEventListener('abort', listener));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,7 +2,7 @@ import { wrap } from 'comlink';
|
||||
import { BridgeMethods, methodNames } from './meta';
|
||||
import workerURL from 'omt:../../../features-worker';
|
||||
import type { ProcessorWorkerApi } from '../../../features-worker';
|
||||
import { abortable } from '../util';
|
||||
import { abortableFunc } from '../util';
|
||||
|
||||
/** How long the worker should be idle before terminating. */
|
||||
const workerTimeout = 10_000;
|
||||
@ -40,29 +40,21 @@ for (const methodName of methodNames) {
|
||||
this._queue = this._queue
|
||||
// Ignore any errors in the queue
|
||||
.catch(() => {})
|
||||
.then(async () => {
|
||||
if (signal.aborted) throw new DOMException('AbortError', 'AbortError');
|
||||
.then(() =>
|
||||
abortableFunc(signal, async (setOnAbort) => {
|
||||
clearTimeout(this._workerTimeout);
|
||||
if (!this._worker) this._startWorker();
|
||||
|
||||
clearTimeout(this._workerTimeout);
|
||||
if (!this._worker) this._startWorker();
|
||||
setOnAbort(() => this._terminateWorker());
|
||||
|
||||
const onAbort = () => this._terminateWorker();
|
||||
signal.addEventListener('abort', onAbort);
|
||||
|
||||
return abortable(
|
||||
signal,
|
||||
// @ts-ignore - TypeScript can't figure this out
|
||||
this._workerApi,
|
||||
).finally(() => {
|
||||
// No longer care about aborting - this task is complete.
|
||||
signal.removeEventListener('abort', onAbort);
|
||||
|
||||
// Start a timer to clear up the worker.
|
||||
this._workerTimeout = setTimeout(() => {
|
||||
this._terminateWorker();
|
||||
}, workerTimeout);
|
||||
});
|
||||
});
|
||||
return this._workerApi.finally(() => {
|
||||
// Start a timer to clear up the worker.
|
||||
this._workerTimeout = setTimeout(() => {
|
||||
this._terminateWorker();
|
||||
}, workerTimeout);
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return this._queue;
|
||||
} as any;
|
||||
|
Reference in New Issue
Block a user