mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-27 11:15:23 +00:00
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
/**
|
|
* abortable.ts — race a promise against an AbortSignal without cancelling the
|
|
* underlying work.
|
|
*
|
|
* Used by the `get_subagent_result` wait paths (top-level and nested): pressing
|
|
* Esc cancels only the caller's wait; the background child keeps running and its
|
|
* result stays unconsumed. The listener is removed on every settle path so the
|
|
* signal accumulates no handlers, and a late settlement of the wrapped promise
|
|
* after an abort is absorbed as a no-op (no unhandled rejection).
|
|
*/
|
|
|
|
/** Await a promise until it settles or the caller cancels, without aborting the underlying work. */
|
|
export function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
if (!signal) return promise;
|
|
if (signal.aborted) return Promise.reject(signal.reason);
|
|
|
|
return new Promise<T>((resolve, reject) => {
|
|
let settled = false;
|
|
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
const onAbort = () => {
|
|
if (settled) return;
|
|
settled = true;
|
|
cleanup();
|
|
reject(signal.reason);
|
|
};
|
|
|
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
promise.then(
|
|
(value) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
cleanup();
|
|
resolve(value);
|
|
},
|
|
(error: unknown) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
cleanup();
|
|
reject(error);
|
|
},
|
|
);
|
|
});
|
|
}
|