Search code examples
javascriptperformancepromisebluebird

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


When using Promise.all with asynchronous code (in case of synchronous code, there is nothing to worry about), you can suffer from severe performance (if not other kinds of) issues, when you want to send out a whole bunch (be it tens, hundreds, thousands or even millions) of requests, given the receiving end of your asynchronous operations (e.g. the local filesystem, an HTTP server, a database, etc etc.) does not gracefully handle that many parallel requests.

For that case, it would be perfect if we could tell Promise.all up to how many promises we want to have in-flight simultaneously. However, since A+ is supposed to be lean, adding these sorts of fancy features would certainly not make sense.

So what would be a better way of achieving this?


Solution

  • Well, first of all - it's impossible to give a concurrency argument to Promise.all since promises represent already started operations so you cannot queue them or make the wait before executing.

    What you want to perform with limited concurrency is promise returning functions. Lucky for you - bluebird ships with this feature (As of version 2.x) using Promise.map:

     Promise.map(largeArray, promiseReturningFunction, {concurrency: 16});
    

    The concurrency parameter decides how many operations may happen at once - note that this is not a global value - but only for this chain. For example:

    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

    Note that execution order is not guaranteed.