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

Performance considerations with `Promise.all` and a large amount of asynchronous operations

Promise.all 与异步代码一起使用时(如果是同步代码,则无需担心),您可能会遇到严重的性能(如果不是其他类型的话)问题,当您想要发送考虑到异步操作的接收端(例如本地文件系统、HTTP 服务器、数据库等)不能很好地处理那么多请求,请输出一大堆(数十、数百、数千甚至数百万)请求并行请求。

对于这种情况,如果我们能够告诉 Promise.all 我们希望同时进行多少个承诺,那将是完美的。然而,既然 A+ 应该是精简的,添加这些花哨的功能肯定没有意义。

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

由于我无法找到一个预先存在的库来处理 promise 批处理,所以我自己编写了一个简单的原语。它是一个 class,它包装了一个要执行的 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;
})();

嗯,首先 - 不可能给 Promise.all 一个并发参数,因为 promises 表示 已经开始 操作,所以你不能在它们之前排队或等待正在执行。

您想以有限并发执行的是承诺返回函数。幸运的是 - bluebird 附带此功能(从版本 2.x 开始)使用 Promise.map:

 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

请注意,无法保证执行顺序。

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

 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((resolve, reject) => {
 //your logic
 resolve('your output')
   })
}