【问题标题】:Enqueuing simultaneous async requests in a loop在循环中将同时的异步请求排队
【发布时间】:2019-10-03 00:05:55
【问题描述】:

我有一个非常大的 url 列表,我需要使用这些 url 调用多个外部 REST API 端点来获取其余数据。然后将这些数据插入到数据库中。

以下是从 REST API 获取数据并将结果存储到数据库中的代码 sn-p:

// Opening storage model
await storageModel.open();

// Iterate through all the links
for (let idx = 0; idx < links.length; idx++)
{
    console.log("Checking link %j of %j", idx+1, links.length);
    link = links[idx];

    // Getting link data (slow)
    try {
        let data = await checkLinkAndGetData(linkGetter, link);
        await storageModel.insert(data);
    }
    catch (error) {
        // Processing some errors
        ...
    }
}

await storageModel.close();

这段代码的性能很差,因为它会等待 Promises 解决,然后再进行下一个链接。我想要的是“排队”5-10 个异步调用(不等待它们),并且只有在一些“排队”的 Promise 得到解决时才使循环继续到下一个链接。

附:我使用的是原生 Promises,而不是 Bluebird。

【问题讨论】:

  • 是的,所以,不要使用 await。 await 与您尝试做的完全相反。将 promise 收集到一个数组中,然后使用 promise.all 来确定它们何时全部完成。
  • @KevinB,我需要处理 300-50 万个链接。
  • 所以?不会改变 await 不会做你想做的事情的事实。 await 将暂停循环,直到等待的承诺完成。然后它将继续到下一个,依此类推。
  • 获取 500k 长度的数组,将其分成更小的 5-10 个条目块,然后处理它们。
  • @KevinB,Promise.all 将等到所有 Promise 都得到解决,我想在任何排队的 Promise 得到解决时开始处理新链接。

标签: javascript node.js promise async-await


【解决方案1】:

一种选择是一次创建 5-10 个承诺,将它们存储在一个数组中,然后 awaiting Promise.all(promises)。例如:

// Opening storage model
await storageModel.open();

// Iterate through all the links
for (let block = 0; block < links.length; block += 10)
{
    const promises = [];

    // Collect promises in blocks of 10.
    for (let idx = block; idx < links.length && idx < block + 10; idx++)
    {
        console.log("Checking link %j of %j", idx+1, links.length);
        link = links[idx];

        promises.push(checkLinkAndGetData(linkGetter, link));
    }

    try {
        // Wait for all 10 promises to finish (in any order).
        let data = await Promise.all(promises);

        // Still await each insert so that the ordering is maintained.
        for (let idx = 0; idx < data.length; idx++)
        {
            await storageModel.insert(data);
        }
    }
    catch (error) {
        // Processing some errors
        ...
    }
}

await storageModel.close();

【讨论】:

  • 感谢您的回答!其实我想过使用 Promise.all,但是它有很多问题:(1)它会等待所有 10 个请求完成; (2) 如果任何输入的 Promise 被拒绝,返回的 Promise 将被拒绝。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-22
  • 1970-01-01
  • 2019-07-21
  • 1970-01-01
  • 1970-01-01
  • 2017-11-23
相关资源
最近更新 更多