为什么reduce会依次等待promise,而forEach则不会?

问题描述 投票:0回答:1

考虑代码:

const promises = [
  new Promise(r => setTimeout(r, 10000, "Hi")),
  new Promise(r => setTimeout(r, 500, "second")),
  new Promise(r => setTimeout(r, 100, "third"))
];
promises.reduce(async (a, promise) => {
  await a;
const p = await promise;
console.log(p);
}, Promise.resolve());

这段代码的输出是 Hi,first,third,尽管这三个承诺之间存在巨大的时间差异。 我的想法:

在每次迭代中,reduce 回调都会立即返回,并带有同步解析的待处理承诺。因此,其后续的异步操作将等待,直到回调返回的三个 Promise 得到解决。但我仍然不认为输出应该是这样的,因为这三个承诺是独立的 - 每个承诺都创建自己的异步操作链。当第一个回调执行时,该函数立即解析为未定义。然后,异步代码(等待 Promise 和记录三个 Promise 被推迟到下一个事件周期 - 放入微任务队列中)。我认为这发生在reduce 迭代的所有三个promise 上。

但是,在 forEach 循环中,即使使用以下代码,promise 也会按顺序解析:

const promises = [
  new Promise(r => setTimeout(r, 10000, "Hi")),
  new Promise(r => setTimeout(r, 500, "second")),
  new Promise(r => setTimeout(r, 100, "third"))
];
promises.forEach(async promise => {
  // try to force the delay of the "promise" in the promises array.
  await 3;
const p = await promise;
console.log(p);
});

输出是第二、第三、第一。为什么会出现这种情况?

那么为什么会发生这种情况呢?我完全期待一些不同的东西

javascript asynchronous
1个回答
0
投票
const promises = [
  new Promise(r => setTimeout(r, 10000, "Hi")),
  new Promise(r => setTimeout(r, 500, "second")),
  new Promise(r => setTimeout(r, 100, "third"))
];

首先,让我们指出这些代码行立即启动超时。因此,无论稍后发生什么,计时器将始终在 100 毫秒、500 毫秒和 10000 毫秒标记处关闭(加上或减去计时器通常的不准确度)。

await
只是决定您要等待什么。

考虑到这一点,让我们看看 foreach 的情况,因为它是最简单的。我会去掉

await 3
,因为它的作用很小。

promises.forEach(async promise => {
  const p = await promise;
  console.log(p);
});

您的函数首先被调用并承诺 10000ms。您等待 10000 毫秒的承诺,这会导致您的函数返回自己的承诺。

.forEach
不关心你返回什么,所以它会移动到数组中的下一个元素,这就是 500ms 的承诺。您等待 500 毫秒的承诺并返回。那么 100 毫秒的承诺也是如此。

100 毫秒后,最初的承诺得以解决。这意味着函数的第三个实例现在可以恢复,第三个注销。在 500 毫秒处,最初的承诺得到解决,允许函数的第二个实例恢复。最后在 10000 毫秒标记处,函数的第一个实例可以恢复。


现在让我们把注意力转向减速机案例。

promises.reduce(async (a, promise) => {
  await a;
  const p = await promise;
  console.log(p);
}, Promise.resolve());

在第一次迭代中,a 是来自

Promise.resolve
的 Promise,Promise 是 10000ms 的 Promise。您等待
a
,导致您的函数返回一个新的 Promise。我们现在进入第二次迭代。
a
是第一次迭代返回的promise,
promise
是500ms的promise。你等待
a
,并返回一个新的承诺。我们现在进入第三次迭代,
a
是第二次迭代的承诺,
promise
是100毫秒的承诺。您等待
a
并返回承诺。

现在我们已经完成了同步代码,我们可以恢复第一个函数了。第一个函数移至下一行,

await
s
promise
,这是 10000ms 的承诺。该函数此时暂停执行。

稍后,100 毫秒的承诺得以实现。没有什么直接在等待它,所以此时什么也没有发生。再后来,500 毫秒的承诺就解决了。同样,没有什么直接在等待它。甚至后来,10000 毫秒的承诺也得到了解决。这允许恢复第一个功能。它记录“hi”,然后返回,从而解决了它自己的承诺。因为它解决了它的承诺,所以函数 2(耐心地等待

await a
现在可以恢复。然后它等待
promise
,这是 500 毫秒的承诺。这个承诺已经解决了,所以在最短的中断之后它恢复了,记录“second”并返回。这反过来又解锁了promise 3,它等待promise,然后恢复。它注销“third”并完成。

© www.soinside.com 2019 - 2024. All rights reserved.