【发布时间】:2017-08-11 07:25:33
【问题描述】:
上下文:我需要进行大量可并行化的异步调用(想想大约 300 到 3000 个 ajax 调用)。但是,我不想通过一次调用它们来使浏览器或服务器紧张。我也不想按顺序运行它们,因为完成需要很长时间。我决定一次运行五个左右,并派生了这个函数:
async function asyncLoop(asyncFns, concurrent = 5) {
// queue up simultaneous calls
let queue = [];
for (let fn of asyncFns) {
// fire the async function and add its promise to the queue
queue.push(fn());
// if max concurrent, wait for the oldest one to finish
if (queue.length >= concurrent) {
await queue.shift();
}
}
// wait for the rest of the calls to finish
await Promise.all(queue);
};
其中 asyncFns 是一个可迭代的(尚未调用的)异步函数。
问题:这可行,但是我发现最老的不是第一个完成的并不总是正确的。我想修改函数,使其使用Promise.race 等到第一个承诺成功,然后从那里继续。但是,我不知道要删除哪个承诺:
// if max concurrent, wait for the first one to finish
if (queue.length >= concurrent) {
await Promise.race(queue);
// ??? get race's completed promise
// queue.splice(queue.indexOf(completed), 1);
}
如果我只知道哪个完成的索引,我可以将它从队列中拼接出来(我猜现在更像是一组)。看起来我无法从种族返回的派生承诺中得到最初的承诺。有什么建议吗?
【问题讨论】:
-
我的看法是这样的:
const [ idx, result ] = await Promise.race(promisesArr.map((promise, idx) => promise.then((result) => [ idx, result ]);不过这不包括例外情况。为了完成它,我有一个方便的特殊函数 (safelyExecuteAsync),它返回一个元组 [error, result] 的承诺。有了它,代码就变成了:const [ idx, [error, result] ] = await Promise.race(promisesArr.map((promise, idx) => safelyExecuteAsync(promise).then((tuple) => [ idx, tuple ]); -
Promise 返回一个 Promise 对象,但返回的 Promise 对象本身与解析的 Promise 对象不同。它具有相同的值,但包装在不同的 Promise 中。这样想 - Promose.race 函数(或任何其他异步函数)本身有一个设置自己的 Promise 来执行其异步工作。这是来电者唯一能看到的。即使 Promise.race 用作可等待信号量,返回的 Promise 本身也没有用(值可以重复)。
标签: javascript asynchronous async-await es6-promise