我怎样才能限制Q promise的并发性?
我如何编写一个限制Q promise并发性的方法?
例如,我有一个方法spawnProcess
。 它返回一个Q的承诺。
我不想每次都产生超过5个进程,但是对于调用代码是透明的。
我需要实现的是带签名的函数
function limitConcurrency(promiseFactory, limit)
我可以打电话给我
spawnProcess = limitConcurrency(spawnProcess, 5); // use spawnProcess as usual
我已经开始编写我的版本了,但是我想知道是否有人可以简单的实现我可以检查的版本。
我有一个库为你做这个https://github.com/ForbesLindesay/throat
您可以通过browserify使用它,或者从brcdn下载独立的版本( https://www.brcdn.org/?module=throat&version=latest )并将其添加为脚本标记。
然后(假设Promise
构造函数是在您的环境中进行填充或实现的),您可以这样做:
//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)); } }
你可以直接调用throat(promiseFactory, limit)
,但是这会返回一个promise promise而不是Q promise。
我也很喜欢用它与array.map。
// only allow 3 parallel downloads var downloadedItems = Q.all(items.map(throat(download, 3)));
这似乎是为我工作。
我不确定我是否可以简化它。 scheduleNextJob
的recursion是必要的,所以running < limit
和limit++
总是在同一个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 }
延期承诺实现具有gate
function,其function正是如此:
spawnProcess = deferred.gate(spawnProcess, 5);
我写了一个小库来做到这一点: https : //github.com/suprememoocow/qlimit
这是非常容易使用,是专门devise与Q承诺工作:
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); }));
它也可以用来限制并发到一个特定的资源,如下所示:
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' }); });