Javascript 正在取消包含等待任务列表的函数

Javascript Canceling Function that contains list of await tasks

我想知道是否可以取消/停止执行包含多个 await 函数的 javascript 函数。由于承诺的性质及其缺乏适当的取消,是否有任何其他实现或库可以帮助我实现这样的目标?

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


实际使用取消的方法是通过浏览器和 Node 15+ 上可用的 AbortController

节点参考:https://nodejs.org/api/globals.html#class-abortcontroller

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

一些 API 目前正在使用开箱即用的中止信号,例如浏览器中的获取或节点中的 setTimeout 计时器 API (https://nodejs.org/api/timers.html#timerspromisessettimeoutdelay-value-options)。

对于自定义 functions/APIs,您需要自己实现它,但强烈建议您遵循中止信号方法,这样您就可以链接自定义和 oob 函数,并使用不需要转换的单个信号

要停止从一个函数调用到下一个函数调用的进展,您可以这样做:

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 没有通用的方法来“中止”函数的任何进一步执行。您可以通过外部函数设置标志,然后在函数的各个点检查该标志,并根据该标志调整执行的内容。

请记住(使用 workerThreads 或 webWorkers 时除外),Javascript 运行 将您的代码放在单个线程中,因此当它处于 运行ning 时,它是 运行ning 和 none 你的其他代码是 运行ning。只有当它 returns 控制回到事件循环(通过返回或通过点击 await)时,您的任何其他代码才有机会 运行 并做任何事情。因此,“当它实际上是 运行ning 时”,您的其他代码将不会是 运行ning。当它位于 await 时,您的其他代码可以 运行 并且可以设置一个可以稍后检查的标志(如我上面的示例所示)。

fetch() 在浏览器中有一些 experimental support 用于 AbortController 接口。但是,请理解一旦请求被发送,它已经被发送并且服务器将接收它。您可能不会中止服务器正在执行的任何操作。如果响应仍未返回或正在返回,您的中止可能会中断它。由于您无法真正知道什么被中止,我认为最好只检查您自己的代码,这样您就不会处理响应或根据您设置的标志进行进一步处理。

如果需要,您可以将此标志检查包装到 AbortController 接口中,但它不会以任何方式改变根本问题 - 它只会影响您为调用中止而公开的 API。