I'm looking to cancel an asynchronous function based on a signal that can be controlled by anything, similar to how a fetch can be aborted through the use of an AbortController - effectively terminating the execution of the async function if the signal is aborted.
The only valid solution I've come across so far is to just continually check if the signal that I'm listening for is true. However, this introduces an extra amount of verbosity to the code which is the main problem with this solution. Otherwise, it looks like NodeJS can't actually terminate functions based on a signal.
I was hoping to use a solution that's syntatically similar to the following:
async function someLongFunctionWithSteps(abortSignal) {
abortSignal.on("abort", () => throw new Error("aborted."));
let one = await stepOneIsLongAndAsync();
let two = await stepTwoIsAlsoLong().then(() => doAnotherThing());
await stepThree(one+two).then(andAnother).catch(butCatch);
let result = await stepFour();
if (result) await stepFiveA();
else await stepFiveB();
try {
await stepSix().then(stepSeven).then(stepEight);
await Promise.all([stepNine, stepTen, stepEleven])
} catch(e) {
console.error(e);
console.error("continuing...");
}
await someCloseOutTask();
}
This exact pattern doesn't work (I think because of how Errors are propogated up the call stack). So this solution doesn't actaully terminate the execution of the someLongFunctionWithSteps. I could place if(abortSignal.aborted) throw new Error("aborted."); in between each async step, however this seems inelegant and something I want to avoid.
I guess this is, in a way, similar to Promise.withResolvers(), however when a Promise is rejected, it still continues to execute its function; its return result is just the rejection instead of the resolution.
Promise.race([abortPromise, someLongFunctionWithSteps]) doesn't work here either, because it'll still execute the whole function which is what I'm trying to avoid.
I've heard that generators could work here, but they create the same code smell problem of putting a condition check between each step.
Is there an elegant method to cancelling/terminating/aborting a Promise/Async function while it's mid-execution? I'm not married to any solution design, although something which makes the code look clean is ideal.
Promiseitself has no first-class protocol for cancellation, but you may be able to directly cancel the underlying asynchronous operation, typically usingAbortController