Home > Net >  Javascript Canceling Function that contains list of await tasks
Javascript Canceling Function that contains list of await tasks

Time:02-16

I was wondering if there is any to cancel / stop execution of a javascript function that contains multiple await functions. Due to the nature of promises and their lack of proper cancellations, is there any other implementation or library to help me achieve something like this?

async function run(x,y,z) {
   return new Promise(async(resolve,reject) => {  
        await doSomething(x)
        await doSomething(y)
        //cancel could be happen around here and stop the last "doSomething"
        await doSomething(z)
   })
}

setTimeout(() => {
     run.cancel()
},500) //cancel function after 500ms


CodePudding user response:

To just stop the advancement from one function call to the next, you can do something like this:

function run(x, y, z) {
    let stop = false;
    async function run_internal() {
        await doSomething(x)
        if (stop) throw new Error("cancelled");
        await doSomething(y)
        if (stop) throw new Error("cancelled");
        await doSomething(z)
    }
    return {
        cancel: () => {
            stop = true;
        },
        promise: run_internal();
    };
}

const retVal = run(a, b, c);
retVal.promise.then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
})

setTimeout(() => {
    retVal.cancel()
}, 500); //cancel function after 500ms

Javascript does not have a generic way to "abort" any further execution of a function. You can set a flag via an external function and then check that flag in various points of your function and adjust what you execute based on that flag.

Keep in mind that (except when using workerThreads or webWorkers), Javascript runs your code in a single thread so when it's running, it's running and none of your other code is running. Only when it returns control back to the event loop (either by returning or by hitting an await) does any of your other code get a chance to run and do anything. So, "when it's actually running", your other code won't be running. When it's sitting at an await, your other code can run and can set a flag that can be checked later (as my example above shows).

fetch() in a browser has some experimental support for the AbortController interface. But, please understand that once the request has been sent, it's been sent and the server will receive it. You likely won't be aborting anything the server is doing. If the response still hasn't come back yet or is in the process of coming back, your abort may be able to interrupt that. Since you can't really know what is getting aborted, I figure it's better to just put a check in your own code so that you won't process the response or advance to further processing based on a flag you set.

You could wrap this flag checking into an AbortController interface if you want, but it doesn't change the fundamental problem in any way - it just affects the API you expose for calling an abort.

CodePudding user response:

The way to actually use cancellation is through the AbortController which is available in the browser and on Node 15

Node reference: https://nodejs.org/api/globals.html#class-abortcontroller

MDN reference: https://developer.mozilla.org/en-US/docs/Web/API/AbortController

Some APIs are currently using out of the box the abort signal like fetch in the browser or setTimeout timers API in Node (https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options).

For custom functions/APIs you need to implement it by yourself but it's highly encouraged to follow the Abort signal methodology so you can chain both custom and oob functions and make use of a single signal that does not need translation

  • Related