forked from external-repos/squoosh
Compare commits
3 Commits
preprocess
...
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
|
* Take a signal and promise, and returns a promise that rejects with an AbortError if the abort is
|
||||||
* signalled, otherwise resolves with the promise.
|
* signalled, otherwise resolves with the promise.
|
||||||
*/
|
*/
|
||||||
export async function abortable<T>(
|
export function abortable<T>(
|
||||||
signal: AbortSignal,
|
signal: AbortSignal,
|
||||||
promise: Promise<T>,
|
promise: Promise<T>,
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
assertSignal(signal);
|
return abortableFunc(signal, () => promise);
|
||||||
return Promise.race([
|
}
|
||||||
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) => {
|
new Promise<T>((_, reject) => {
|
||||||
signal.addEventListener('abort', () =>
|
listener = () => {
|
||||||
reject(new DOMException('AbortError', 'AbortError')),
|
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 { BridgeMethods, methodNames } from './meta';
|
||||||
import workerURL from 'omt:../../../features-worker';
|
import workerURL from 'omt:../../../features-worker';
|
||||||
import type { ProcessorWorkerApi } from '../../../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. */
|
/** How long the worker should be idle before terminating. */
|
||||||
const workerTimeout = 10_000;
|
const workerTimeout = 10_000;
|
||||||
@@ -40,29 +40,21 @@ for (const methodName of methodNames) {
|
|||||||
this._queue = this._queue
|
this._queue = this._queue
|
||||||
// Ignore any errors in the queue
|
// Ignore any errors in the queue
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.then(async () => {
|
.then(() =>
|
||||||
if (signal.aborted) throw new DOMException('AbortError', 'AbortError');
|
abortableFunc(signal, async (setOnAbort) => {
|
||||||
|
clearTimeout(this._workerTimeout);
|
||||||
|
if (!this._worker) this._startWorker();
|
||||||
|
|
||||||
clearTimeout(this._workerTimeout);
|
setOnAbort(() => this._terminateWorker());
|
||||||
if (!this._worker) this._startWorker();
|
|
||||||
|
|
||||||
const onAbort = () => this._terminateWorker();
|
return this._workerApi.finally(() => {
|
||||||
signal.addEventListener('abort', onAbort);
|
// Start a timer to clear up the worker.
|
||||||
|
this._workerTimeout = setTimeout(() => {
|
||||||
return abortable(
|
this._terminateWorker();
|
||||||
signal,
|
}, workerTimeout);
|
||||||
// @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._queue;
|
return this._queue;
|
||||||
} as any;
|
} as any;
|
||||||
|
|||||||
Reference in New Issue
Block a user