How Can I Limit Q Promise Concurrency?
Solution 1:
I have a library that does this for you https://github.com/ForbesLindesay/throat
You can use it via browserify or download the standalone build from brcdn (https://www.brcdn.org/?module=throat&version=latest) and add it as a script tag.
Then (assuming the Promise constructor is polyfilled or implemented in your environment) you can do:
//remove this line if using standalone build
var throat = require('throat');
function limitConcurrency(promiseFactory, limit) {
  var fn = throat(promiseFactory, limit);
  return function () {
    return Q(fn.apply(this, arguments));
  }
}
You could just call throat(promiseFactory, limit) directly but that would return a promise promise rather than a Q promise.
I also really like using it with array.map.
// only allow 3 parallel downloads
var downloadedItems = Q.all(items.map(throat(download, 3)));
Solution 2:
This seems to be working for me.
I'm not sure if I could simplify it. The recursion in scheduleNextJob is necessary so the running < limit and limit++ always execute in the same tick.
'use strict';
var Q = require('q');
/**
 * Constructs a function that proxies to promiseFactory
 * limiting the count of promises that can run simultaneously.
 * @param promiseFactory function that returns promises.
 * @param limit how many promises are allowed to be running at the same time.
 * @returns function that returns a promise that eventually proxies to promiseFactory.
 */
function limitConcurrency(promiseFactory, limit) {
  var running = 0,
      semaphore;
  function scheduleNextJob() {
    if (running < limit) {
      running++;
      return Q();
    }
    if (!semaphore) {
      semaphore = Q.defer();
    }
    return semaphore.promise
      .finally(scheduleNextJob);
  }
  function processScheduledJobs() {
    running--;
    if (semaphore && running < limit) {
      semaphore.resolve();
      semaphore = null;
    }
  }
  return function () {
    var args = arguments;
    function runJob() {
      return promiseFactory.apply(this, args);
    }
    return scheduleNextJob()
      .then(runJob)
      .finally(processScheduledJobs);
  };
}
module.exports = {
  limitConcurrency: limitConcurrency
}
Solution 3:
The Deferred promise implementation has gate function which works exactly that way:
spawnProcess = deferred.gate(spawnProcess, 5);    
Solution 4:
I wrote a little library to do this: https://github.com/suprememoocow/qlimit
It's extremely easy to use and is specifically designed to work with Q promises:
var qlimit = require('qlimit');
var limit = qlimit(2); // 2 being the maximum concurrency
// Using the same example as above
return Q.all(items.map(limit(function(item, index, collection) { 
  return performOperationOnItem(item);
}));
It can also be used to limit concurrency to a specific resource, like this:
var qlimit = require('qlimit');
var limit = qlimit(2); // 2 being the maximum concurrency
var fetchSomethingFromEasilyOverwhelmedBackendServer = limit(function(id) {
  // Emulating the backend service
  return Q.delay(1000)
    .thenResolve({ hello: 'world' }); 
});
Post a Comment for "How Can I Limit Q Promise Concurrency?"