gpt4 book ai didi

javascript - for 循环中的 Promise 是如何工作的?

转载 作者:行者123 更新时间:2023-12-05 00:28:34 25 4
gpt4 key购买 nike

在我的程序源代码中我有以下函数(Promise 并发限制函数,类似于 pLimit):

async function promiseMapLimit(
array,
poolLimit,
iteratorFn,
) {
const ret = [];
const executing = [];
for (const item of array) {
const p = Promise.resolve().then(() => iteratorFn(item, array));
ret.push(p);

if (poolLimit <= array.length) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= poolLimit) {
await Promise.race(executing);
}
}
}

return Promise.all(ret);
}
它工作正常,所以如果我传递给它一个数字数组 [1..99] 并尝试将它乘以 2,它将给出正确的输出 [0..198]。
const testArray = Array.from(Array(100).keys());

promiseMapLimit(testArray, 20, async (value) => value * 2).then((result) =>
console.log(result)
);
代码示例 - js playground .
但是我无法理解它的逻辑,在我注意到的调试过程中,它以 20 个为一组添加了 Promise,并且只有在这之后才会更进一步:
enter image description here
例如,这个代码块:
  for (const item of array) {
const p = Promise.resolve().then(() => iteratorFn(item, array));
ret.push(p);
将迭代数组的 20 项以上( 为什么不是全部 100 项???)
同样在这里:
if (poolLimit <= array.length) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
它只会将 20 项添加到 executing数组,并且只有在 if (executing.length >= poolLimit) 内的那一步之后代码块。
非常感谢您解释此功能的工作原理。

最佳答案

非常有趣的问题!我认为这里代码的重要部分是Promise.race(...)只要其中一个 promise 解决,它就会解决。
我添加了一个 sleep使用随机因子(最多 6 秒)来更好地可视化其工作方式。
预期的功能是:我们总是希望并行执行 20 个 Promise,一旦一个完成,队列中的下一个就会执行。
在视觉上,这看起来像这样,对于 3 和 10 个 promise 的限制 - 在下面的示例中,您可以注意到在每个时刻都有 3 个有效的 promise (除了它们结束时):

PromiseID  | Start                 End |
0 [====]
1 [==]
2 [======]
3 [==========]
4 [====]
5 [================]
6 [==]
7 [====]
8 [======]
9 [========]
创建随机延迟的代码如下:

// Create the utility sleep function
const sleep = x => new Promise(res => setTimeout(res, x))

async function promiseMapLimit(array, poolLimit, iteratorFn) {
const ret = [];
const executing = [];
for (const item of array) {
const p = Promise.resolve().then(() => iteratorFn(item, array));
ret.push(p);

console.log(ret.length)
if (poolLimit <= array.length) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= poolLimit) {
console.log(`Running batch of ${executing.length} promises.`);
await Promise.race(executing);
// As ssoon one of the promise finishes, we continue the loop.
console.log("Resolved one promise.")
}
}
}

return Promise.all(ret);
}

const testArray = Array.from(Array(100).keys());

promiseMapLimit(testArray, 20, async (value) => {
// Log
console.log(`Computing iterator fn for ${value}`)
await sleep(3000 + Math.random() * 3000);
return value * 2
}).then((result) =>
console.log(result)
);

will iterate over 20 items of an array (why not all 100???)


在开始时,就像在图表中一样,它不会迭代所有 100 个项目,而是前 20 个项目,然后循环被 await Promise.race(...) 暂停(因为 executing.length >= poolLimit 将在迭代 20 个项目后为真)。
一旦一个 promise 完成,它就会从 executing 中删除。数组由 executing.splice(executing.indexOf(e), 1) .
我认为当有延迟( await sleep(...) )时事情会变得更加清晰,以便我们可以模拟真正的异步操作(例如数据库请求等)。
如果还有其他不清楚的地方,请告诉我。

关于javascript - for 循环中的 Promise 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70124591/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com