在循环中同时排队异步请求

时间:2019-05-15 19:14:55

标签: javascript node.js promise async-await

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

下面是从REST API获取数据并将结果存储到数据库中的代码段:

// 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个异步调用(而不必等待它们),并且仅当某些“排队”的承诺得到解决时,才使循环继续进行下一个链接。

P.S。我使用的是本地Promises,而不是Bluebird。

1 个答案:

答案 0 :(得分:2)

一种选择是一次创建5-10个承诺,将它们存储在一个数组中,然后await添加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();