【问题标题】:NodeJS Promise.all is waiting for all components to finish before continuingNodeJS Promise.all 正在等待所有组件完成后再继续
【发布时间】:2018-12-28 11:10:13
【问题描述】:

我正在尝试处理由对象组成的数组。每个对象都有一个字段,其值是一个数字数组。我想以异步/等待方式处理所有数字数组的所有组件。

数据示例如下:

const data = [{
  numbers: [1, 2, 3],
}, {
  numbers: [4, 5, 6],
}, {
  numbers: [7, 8, 9],
}];

我已经通过两种方式实现了这个功能。第一个代码是这样的:

const processData1 = async(data) => {
  return Promise.all(data.map(async(d) => {
    const partial = await Promise.all(d.numbers.map(async(n) => {
      console.log('INIT', n);
      const number = await processNumber(n);
      console.log('END', n);
      return number;
    }));
    return partial;
  }));
};

第二个是这样的:

const processData2 = async(data) => {
  for (const d of data) {
    for (let n of d.numbers) {
      console.log('INIT', n);
      n = await processNumber(n);
      console.log('END', n);
    }
  }
};

我希望在控制台中打印的所有情况下都以正确的顺序依次显示“INIT”和“END”。这在第二个代码函数中是正确的。但在第一个中,我看到与数字一样多的 INIT,然后是所有相应的 END:

**** processData1 ****
INIT 1
INIT 2
INIT 3
INIT 4
INIT 5
INIT 6
INIT 7
INIT 8
INIT 9
END 1
END 2
END 3
END 4
END 5
END 6
END 7
END 8
END 9
**** processData2 ****
INIT 1
END 1
INIT 2
END 2
INIT 3
END 3
INIT 4
END 4
INIT 5
END 5
INIT 6
END 6
INIT 7
END 7
INIT 8
END 8
INIT 9
END 9

这怎么可能?为什么await processNumber 等待所有号码都被解析?

【问题讨论】:

  • d.numbers.map(async(n)... 将在循环中创建异步函数,这些函数将同时执行,因为在每个结束之前 INIT 一个接一个地出现

标签: javascript node.js promise async-await


【解决方案1】:

在第一个示例中,您只等待Promise.all 的结果,这意味着每个承诺同时执行。在第二个示例中,您等待每个单独的 Promise,这会强制它们按顺序执行。

这两种情况都有其用途,如果您不关心顺序,第一种情况会更好,即操作可以同时运行,第二种情况对于强制异步代码按顺序执行很有用。

【讨论】:

  • Promise 不会被“解雇”,Promise.allawait 都不会。
  • @Bergi 我没有说他们是,我只是说他们是同时被解雇的(或者立即可能更准确)。
  • 在第一个例子中,我只在第二个 Promise.all 中使用 await,但当我使用 return 时,它应该等待它完成
  • @user3748883 map 回调函数确实在记录END 并解析调用返回的承诺之前等待它完成。但这并不能阻止 map 独立调用每个元素的回调,立即创建一个 Promise 数组。
  • @user3748883 不完全是,numbers.map 为列表中的每个项目创建一个承诺,它将同时排队。在每个 Promise 中都有一个 await,它将把每个 Promise 中的第二个代码块放回队列中,在此期间事件循环继续处理其他排队的代码(即所有其他 Promise)。这就是为什么您首先收到所有 INIT 消息,然后是所有 END 消息。
【解决方案2】:

来自MDN

Promise.all(iterable) 方法返回一个 Promise 当可迭代参数中的所有承诺都具有时解决 已解决或当可迭代参数不包含任何承诺时。它 以第一个拒绝的承诺的原因拒绝。

这意味着传递的 Promise 都是并行执行的,只有当所有的 Promise 都结束时才会完成和解决。在您的示例中,子承诺被授予按顺序启动。在您的情况下,它们碰巧以相同的顺序结束,但这不一定能保证(一个可能需要比另一个更长的时间并在之后结束)。

对于第二个示例,您所做的只是启动并立即等待 for 循环中的每个 processNumber(n),从而导致每个进程按顺序开始和结束。

【讨论】:

  • Promise.all 不会“启动”任何承诺
  • 期待您的回答@Bergi!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-25
  • 2019-11-01
  • 2021-05-06
  • 2021-05-21
  • 2015-10-03
  • 2013-11-25
相关资源
最近更新 更多