限制正在运行的promise的并发性

我正在寻找一个承诺函数包装,可以限制/节stream,当一个给定的承诺运行,以便只有一个数量的承诺运行在给定的时间。

在下面的情况下, delayPromise不应该同时运行,他们应该以先来先服务的顺序一次运行一个。

 import Promise from 'bluebird' function _delayPromise (seconds, str) { console.log(str) return Promise.delay(seconds) } let delayPromise = limitConcurrency(_delayPromise, 1) async function a() { await delayPromise(100, "a:a") await delayPromise(100, "a:b") await delayPromise(100, "a:c") } async function b() { await delayPromise(100, "b:a") await delayPromise(100, "b:b") await delayPromise(100, "b:c") } a().then(() => console.log('done')) b().then(() => console.log('done')) 

任何想法如何获得像这样的队列设置?

我有一个美妙的Benjamin Gruenbaum “debounce”function。 我需要修改这个基于它自己的执行而不是延迟来限制承诺。

 export function promiseDebounce (fn, delay, count) { let working = 0 let queue = [] function work () { if ((queue.length === 0) || (working === count)) return working++ Promise.delay(delay).tap(function () { working-- }).then(work) var next = queue.shift() next[2](fn.apply(next[0], next[1])) } return function debounced () { var args = arguments return new Promise(function (resolve) { queue.push([this, args, resolve]) if (working < count) work() }.bind(this)) } } 

我不认为有任何图书馆可以这样做,但是实现自己却很简单:

 function queue(fn) { // limitConcurrency(fn, 1) var q = Promise.resolve(); return function(x) { var p = q.then(function() { return fn(x); }); q = p.reflect(); return p; }; } 

对于多个并发请求,它有点棘手,但也可以做到。

 function limitConcurrency(fn, n) { if (n == 1) return queue(fn); // optimisation var q = null; var active = []; function next(x) { return function() { var p = fn(x) active.push(p.reflect().then(function() { active.splice(active.indexOf(p), 1); }) return [Promise.race(active), p]; } } function fst(t) { return t[0]; } function snd(t) { return t[1]; } return function(x) { var put = next(x) if (active.length < n) { var r = put() q = fst(t); return snd(t); } else { var r = q.then(put); q = r.then(fst); return r.then(snd) } }; } 

顺便说一句,你可能想看看演员模型和CSP 。 他们可以简化处理这些事情,也有一些JS库在那里。

 import Promise from 'bluebird' function sequential(fn) { var q = Promise.resolve(); return (...args) => { const p = q.then(() => fn(...args)) q = p.reflect() return p } } async function _delayPromise (seconds, str) { console.log(`${str} started`) await Promise.delay(seconds) console.log(`${str} ended`) return str } let delayPromise = sequential(_delayPromise) async function a() { await delayPromise(100, "a:a") await delayPromise(200, "a:b") await delayPromise(300, "a:c") } async function b() { await delayPromise(400, "b:a") await delayPromise(500, "b:b") await delayPromise(600, "b:c") } a().then(() => console.log('done')) b().then(() => console.log('done')) // --> with sequential() // $ babel-node test/t.js // a:a started // a:a ended // b:a started // b:a ended // a:b started // a:b ended // b:b started // b:b ended // a:c started // a:c ended // b:c started // done // b:c ended // done // --> without calling sequential() // $ babel-node test/t.js // a:a started // b:a started // a:a ended // a:b started // a:b ended // a:c started // b:a ended // b:b started // a:c ended // done // b:b ended // b:c started // b:c ended // done 

我也有同样的问题。 我写了一个库来实现它。 代码在这里 。 我创build了一个队列来保存所有的承诺。 当你向队列推送一些承诺时,队列头部的前几个承诺将被popup并运行。 一旦一个承诺完成,队列中的下一个承诺也将被popup并运行。 一次又一次,直到队列没有Task 。 你可以查看代码的细节。 希望这个图书馆能帮助你。

使用throttled-promise模块:

https://www.npmjs.com/package/throttled-promise

 var ThrottledPromise = require('throttled-promise'), promises = [ new ThrottledPromise(function(resolve, reject) { ... }), new ThrottledPromise(function(resolve, reject) { ... }), new ThrottledPromise(function(resolve, reject) { ... }) ]; // Run promises, but only 2 parallel ThrottledPromise.all(promises, 2) .then( ... ) .catch( ... ); 

运行asynchronous进程的经典方法是使用async.js并使用async.series() 。 如果您更喜欢基于承诺的代码,那么有一个承诺版本的async.js : async-q

使用async-q您可以再次使用series

 async.series([ function(){return delayPromise(100, "a:a")}, function(){return delayPromise(100, "a:b")}, function(){return delayPromise(100, "a:c")} ]) .then(function(){ console.log(done); }); 

同时运行其中两个将同时运行ab但在每个运行中它们将是连续的:

 // these two will run concurrently but each will run // their array of functions sequentially: async.series(a_array).then(()=>console.log('a done')); async.series(b_array).then(()=>console.log('b done')); 

如果你想在b之后运行b ,那么把它放在.then()

 async.series(a_array) .then(()=>{ console.log('a done'); return async.series(b_array); }) .then(()=>{ console.log('b done'); }); 

如果不是按顺序运行,而是想限制每个进程同时运行一组进程,那么可以使用parallelLimit()

 // Run two promises at a time: async.parallelLimit(a_array,2) .then(()=>console.log('done')); 

阅读async-q文档: https : //github.com/dbushong/async-q/blob/master/READJSME.md