【问题标题】:Javascript cancel async for loopJavascript取消异步for循环
【发布时间】:2021-02-21 18:43:43
【问题描述】:

我在一个项目中找到了这段代码:

const fn = async () => {
    let x = 0;
    for(let i = 0; i < 50; i++){
        const res = await api.call(i);
        if(res.someProp) x++;
    }

    return x;
}

我希望能够在中途停止它,这样如果我再次调用它,它将从头开始并丢弃之前的调用结果。避免同时发出两组请求。

【问题讨论】:

  • 您不能在中途停止等待呼叫。您可以使用标志变量将其锁定以防止一次重复调用。
  • 在 JS 中使用 async 和 await 基本上是对使用 Promises 和 then( ) 的语法糖衣。承诺一旦触发就不能中途停止。但是,如果有任何安慰,同步代码总是先执行,然后执行诸如 Promise 之类的微任务,最后执行来自回调队列的回调,因此尽管此 API 调用肯定会给您的应用程序增加一些负载,但它将是异步的,并且后台进程。
  • 你可以 break; 退出 for 循环,所以你可以做的是检查循环内的全局标志变量(如 stopLoop),如果为真则中断。如果您希望循环重新开始,您还可以在循环内将 x 和 i 重置为 0(并将 stopLoop 重置为 false)。
  • @ChrisG 我认为这个想法是,如果它正在等待 api.call 完成,并且最初调用 fn 的代码决定放弃。它如何取消整个链而不显式传递下面每个 api 必须支持的参与式取消对象。在某些时候,它可能正在等待一个不参与的低级异步调用。所以我认为问题在于如何拆除承诺链并取消它。 (FWIW,我认为答案是你不能,你必须在可以这样做的级别上添加一些显式的取消处理。)

标签: javascript loops async-await cancellation


【解决方案1】:

应该这样做:

let token;
const fn = async () => {
    const my = token = Symbol();
    let x = 0;
    for(let i = 0; i < 50 && my == token; i++){
        const res = await api.call(i);
        if(res.someProp) x++;
    }

    return x;
}

虽然调用之间仍有一些重叠,但任何先前的循环都会在下一个 fn() 调用开始时中断它们的迭代。

【讨论】:

  • 这是一个很好的答案,我不知道为什么一年多来没有投票或 cmets!
【解决方案2】:

您可以使用任何使用外部标志变量的技术来中断循环。

作为一种解决方法,您可以尝试使用自定义 Promise 类 (Live demo):

import CPromise from "c-promise2";

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function api(i) {
  console.log(`Async API call [${i}]`);
  await delay(100);
  return {};
}

const fn = () =>
  CPromise.from(function* () {
    let x = 0;
    for (let i = 0; i < 50; i++) {
      const res = yield api.call(i);
      if (res.someProp) x++;
    }

    return x;
  });

const cancelablePromise = fn().then(
  () => console.log("Done"),
  (err) => console.log(`Fail: ${err}`) // Fail: CanceledError: canceled 
);

setTimeout(() => {
  cancelablePromise.cancel(); // abort the async sequence (loop) after 3500ms
}, 3500);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多