【问题标题】:Why the execution doesn't stop at await (async/await JS)?为什么执行不会在 await (async/await JS) 处停止?
【发布时间】:2021-09-17 06:04:35
【问题描述】:

我正在编写一个函数,它应该尽可能快地执行所有异步函数,但是,其中只有 5 个可以同时运行。

我想使用Promise.race 来实现,所以实现不是最好的。问题是代码执行不会在await 处停止。我希望,counter 变量只有在承诺解决但不等待承诺解决时才会减少。代码也不会停在Promise.all,这让我觉得我对 Promise 的理解是不正确的。代码如下,有问题的函数是runPromises

async function runPromises(promises, limit) {
  const LIMIT = limit || 10;
  let promsCopy = promises.slice();
  let counter = 0;
  let queue = [];
  while (promsCopy.length !== 0) {
    if (counter < LIMIT) {
      let prom = promsCopy.shift();
      if (prom) {
        queue.push(prom());
        counter += 1;
        if (counter >= LIMIT) {
          let [completed] = await Promise.race(
            queue.map((p) => p.then((_) => [p]))
          );
          queue.splice(queue.indexOf(completed), 1);
          counter -= 1;
        }
      }
    }
  }
  await Promise.all(queue);
}

// the code below is just for testing

const asyncFuncLong = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 6000);
  });
};

const asyncFuncShort = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 1000);
  });
};

let fns = [
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
  asyncFuncLong,
];

let start = Date.now();

runPromises(fns, 10).then(() => {
  console.log(Date.now() - start);
});


编辑:已修复。现在一切正常。谢谢两位!

【问题讨论】:

  • 我不能使用await 语法然后我相信?
  • 你为什么还要在这里使用new Promise?您可以并且应该在 runPromises 内部使用 await,这已经是一个 async 函数。
  • 我现在已经修复了它,但遇到了一个不同的问题,即只解决了第一个承诺。
  • 我想我有点误解了意图。如果您确实选择了let promises = fns.map((f) =&gt; f());,那么这会立即“启动”所有承诺。所以他们都在等待 6 秒,但同时。为了一个接一个地启动它们,您确实需要将它们保留为函数,然后再调用它们。

标签: javascript asynchronous async-await promise


【解决方案1】:

fns 数组是一个函数列表。这些函数返回 Promise 对象。然后,您将该函数列表传递给您的 runPromises 函数,该函数似乎想要将 Promise 对象列表作为参数。但是你传递给它一个函数列表。

我的建议是

  • 更改runPromises 函数,使其在某个时刻实际调用prom()(或仅使用映射,如const r = await Promise.all(queue.map((fn) =&gt; { return fn(); }));),或

  • fns 的定义更改为let fns = [ asyncFuncLong(), asyncFuncShort(), asyncFuncLong(), ... ];

【讨论】:

  • 第二个建议不起作用,因为它会立即运行所有调用。
  • 函数立即返回 Promise 对象,表示异步任务不一定执行完毕。
  • 是的,但如果你这样做了,你所能做的就是将承诺数组传递给Promise.all,并发任务没有限制。
  • 是的,没错。我稍微误解了程序的意图。我明白你的意思了;本质上它一次启动所有计时器,这不是预期的。它确实允许你等待所有的承诺完成,只是方式不正确。
猜你喜欢
  • 2017-10-26
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-27
  • 1970-01-01
相关资源
最近更新 更多