大型阵列映射中的速率限制承诺

时间:2016-06-03 21:04:15

标签: javascript arrays asynchronous queue promise

我目前正在尝试输入下面的数组phoneNumbers。示例数组有2个电话号码,工作正常,但我的实际数组包含数千个数字。

当我尝试使用promise.all并将电话号码映射到名称时,我收到连接错误,因为它花了这么长时间。如何使用promises(或类似的东西)在阵列中一次使用50或100?

var phoneNumbers = [4444444444, 5555555555];

var answer = client.Answer;
return Promise.all(phoneNumber.map(id => Answer.findThing(id, {
    attributes: ["name", "state"]
}))).then(problems => {
    for (var p = 0; p < problems.length; p++) {
        var phoneNames = problems[p].name;
    }
})

2 个答案:

答案 0 :(得分:0)

尝试这样的事情:

var promises = [];
            for (var i = 0; i < phoneNumbers.length; i++) {
                (function () {
                    var def = new $.Deferred();
                    promises.push(def);
                    var j = i;
                    asyncFunction(phoneNumbers[j]).then(function (data) {
                        //do whatever here
                        def.resolve();
                    })
                })();
            }
            var completePromise= $.when.apply(undefined, promises).promise();

当已解决completedPromise时,您知道所有电话号码都已由______ asyncFunction处理。它应该允许同时处理许多,虽然我只在生产中使用几百而不是数千运行此代码。

答案 1 :(得分:0)

在这些行之间进行读取,看起来你想要返回一个名字数组的承诺。

如果是这样,您可以按如下方式整理代码:

// ES6 native Promise
// n parallel requests
var phoneNumbers = [4444444444, 5555555555, ...];
var findOptions = { 'attributes': ['name', 'state'] };
return Promise.all(phoneNumbers.map(id => client.Answer.findThing(id, findOptions))).then(problems => problems.map(p => p.name)); 

这只是整理,而不是解决方案。

如果phoneNumbers数组的长度确实是您的错误的来源,那么您需要尝试限制同时挂起的.findThing()请求的数量。最简单的方法(至少在诊断上)是使用Bluebird的.map()及其concurrency选项。

// Bluebird
// n requests but a maximum of 10 (or whatever) concurrently
var phoneNumbers = [4444444444, 5555555555, ...];
var findOptions = { 'attributes': ['name', 'state'] };
var mapOptions =  {concurrency: 10}; //adjust up/down experimentally
return Promise.map(phoneNumbers, id => client.Answer.findThing(id, findOptions), mapOptions).map(p => p.name);

使用原生Promise可以实现相同的效果,但代码不会那么整洁。

如果您发现只有{concurrency: 1}有效,那么Bluebird&#39; Promise.map就是矫枉过正。顺序请求很容易使用本机Promise进行编码:

// ES6 native Promise
// n sequential requests, by building .then chain
var phoneNumbers = [4444444444, 5555555555, ...];
var findOptions = { 'attributes': ['name', 'state'] };
return phoneNumbers.reduce((promise, id) => promise.then(() => client.Answer.findThing(id, findOptions)), Promise.resolve()).then(problems => problems.map(p => p.name));

这可能太缺乏记忆力;如果是这样,那么递归替代方案会更好:

// ES6 native Promise
// n sequential requests, through recursion
var phoneNumbers = [4444444444, 5555555555, ...];
var findOptions = { 'attributes': ['name', 'state'] };
function find(index, results) {
    return (index < phoneNumbers.length) ? client.Answer.findThing(phoneNumbers(index), findOptions).then(p => {
        results.push(p.name);
        return find(index+1, results);
    }) : results;
}
return find(0, []);