考虑代码:
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);
});
输出是第二、第三、第一。为什么会出现这种情况?
那么为什么会发生这种情况呢?我完全期待一些不同的东西
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”并完成。