【问题标题】:Javascript Canceling Function that contains list of await tasks包含等待任务列表的 Javascript 取消函数
【发布时间】:2022-02-16 10:27:31
【问题描述】:

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

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


【问题讨论】:

  • 没有承诺。 Observables 是你想要研究的东西。
  • 您的实际doSomething() 中有什么。请显示真实代码,而不是理论代码,因为我们可以为您提供更好的帮助。如何中止 nodejs 或浏览器中的某些内容完全取决于操作是什么。中止没有通用的答案。
  • 另外,将现有的返回承诺的操作包装在你自己的新承诺中是一种承诺反模式。不应该那样做。
  • @jfriend00 doSomething() 函数主要是获取请求和数据解析这些请求,每个函数可能需要大约 250 - 1000 毫秒
  • @Seti 观察者的问题是它实际上并没有停止代码执行,而是提供了一个窗口,让我们知道何时可以返回一个值。

标签: javascript node.js promise es6-promise cancellation


【解决方案1】:

要停止从一个函数调用到下一个函数调用的进展,您可以执行以下操作:

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 在单个线程中运行您的代码,因此当它运行时,它正在运行,而您的其他代码都没有运行。只有当它将控制权返回给事件循环(通过返回或通过点击await)时,您的任何其他代码才有机会运行并执行任何操作。因此,“当它实际运行时”,您的其他代码将不会运行。当它位于await 时,您的其他代码可以运行并可以设置一个以后可以检查的标志(如我上面的示例所示)。

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

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

【讨论】:

  • 虽然我宁愿远离这种方法,但它似乎是唯一可以使用 JS 和自定义异步函数的方法。
【解决方案2】:

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

节点引用:https://nodejs.org/api/globals.html#class-abortcontroller

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

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

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

【讨论】:

  • 所以我基本上会将中止信号应用于“运行”功能。因此完全停止该函数的代码执行?
  • @user16180718 - 除了 Javascript 中没有“停止该函数的代码执行”的机制。 AbortController 只是一个公开中止操作的 API。您自己的代码必须弄清楚如何实际中止某事。
猜你喜欢
  • 2017-10-25
  • 2013-07-11
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 1970-01-01
  • 2020-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多