使用`Promise.all`和大量异步操作的性能考虑因素

时间:2015-04-18 19:08:04

标签: javascript performance promise bluebird

Promise.all与异步代码一起使用时(如果是同步代码,没有什么可担心的),当你想发送一个问题时,你会遇到严重的性能(如果不是其他类型的话)鉴于异步操作的接收端(例如本地文件系统,HTTP服务器,数据库等等)没有优雅地处理那么多并行请求,整个请求(数十,数百,数千甚至数百万)请求

对于那种情况,如果我们可以告诉Promise.all我们希望同时在飞行中有多少承诺,那将是完美的。但是,由于A +应该是精益的,添加这些奇特的功能肯定没有意义。

那么实现这一目标的更好方法是什么?

3 个答案:

答案 0 :(得分:5)

嗯,首先 - 不可能给Promise.all一个并发参数,因为promises代表已经启动操作,所以你不能在执行前排队或等待。

有限并发性要执行的是承诺返回函数。幸运的是 - bluebird使用Promise.map

附带此功能(自2.x版开始)
 Promise.map(largeArray, promiseReturningFunction, {concurrency: 16});

并发参数决定一次可以发生多少操作 - 请注意,这不是全局值 - 而是仅针对此链。例如:

Promise.map([1,2,3,4,5,6,7,8,9,10], function(i){
    console.log("Shooting operation", i);
    return Promise.delay(1000);
}, {concurrency: 2});

Fiddle

请注意,不保证执行顺序。

答案 1 :(得分:1)

由于我无法找到预先存在的库来处理承诺批处理,我自己写了一个简单的原语。它是一个包装要执行的function数组的类,并将其分区为给定大小的批处理。它将等待每个批次完成后再运行下一个批次。这是一个相当天真的实现。在一些网络场景中,可能需要一个完整的限制机制。

Fiddle

代码:

/**
 * Executes any number of functions, one batch at a time.
 *
 * @see http://jsfiddle.net/93z8L6sw/2
 */
var Promise_allBatched = (function() {
    var Promise_allBatched = function(arr, batchSize) {
        if (arr.length == 0) return Promise.resolve([]);
        batchSize = batchSize || 10;

        var results = [];
        return _runBatch(arr, batchSize, results, 0)
        .return(results);        // return all results
    };

    function _runBatch(arr, batchSize, results, iFrom) {
        // run next batch
        var requests = [];
        var iTo = Math.min(arr.length, iFrom + batchSize);

        for (var i = iFrom; i < iTo; ++i) {
            var fn = arr[i];
            var request;
            if (fn instanceof Function) {
                request = fn();
            }
            else {
                request = fn;
            }
            requests.push(request);            // start promise
        }

        return Promise.all(requests)        // run batch
        .then(function(batchResults) {
            results.push.apply(results, batchResults);    // store all results in one array

            console.log('Finished batch: ' + results.length + '/' + arr.length);
        })
        .then(function() {
            if (iTo < arr.length) {
                // keep recursing
                return _runBatch(arr, batchSize, results, iTo);
            }
        });
    }

    return Promise_allBatched;
})();

答案 2 :(得分:-1)

let arry=[1,2,4,........etc];//large ammount of arry

 while (arry.length) {
    //I splice the arry 0,10...so you can change the limit as your //wish(note your server should be handle your limit
  Promise.all(arry.splice(0, 10).map(async (eachArryElement) => {
                   let res = await yourAsyncMethod(eachArryElement);
    }))

}

function yourAsyncMethod(data){
 return new Promise((reslove,reject)=>{
 //your logic
 reslove('your output')
   })
}