Limit concurrency promises

I am looking for a promise function wrapper that can limit / throttle when a given promise is fulfilled, so that only a certain amount of this promise works at a given time.

In the case below, delayPromise should never be started at the same time, all of them should be started in turn in the order of first reception.

 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')) 

Any ideas on how to get a queue like this setting?

I have a "debounce" function from the wonderful Benjamin Gruenbaum . I need to change this to dampen a promise based on its own fulfillment, and not on delay.

 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)) } } 
+6
source share
4 answers

I do not think that there are libraries for this, but in fact it is quite simple to implement:

 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; }; } 

For multiple simultaneous requests, this gets a little more complicated, but can be done as well.

 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) } }; } 

By the way, you can take a look at the cast model and CSP . They can make things easier, there are several JS libraries for them.

example

 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 
+6
source

I have the same problem. I wrote a library for its implementation. The code is here . I created a queue to save all promises. When you click on the promises button in the queue, the first few promises at the beginning of the queue will be knocked out and launched. After one promise is made, the next promise in the queue will also be displayed and launched. Again and again until the queue has a Task . You can check the code for details. I hope this library helps you.

0
source

Use a throttle latch module:

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( ... ); 
-1
source

The classic way to start sequential asynchronous processes is to use async.js and use async.series() . If you prefer promise-based code, there is an impoverished version of async.js : async-q

With async-q you can use series again:

 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); }); 

Running two of them at the same time will start a and b at the same time, but inside each of them they will be sequential:

 // 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')); 

If you want to run b after a , put it in .then() :

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

If, instead of starting sequentially in series, you want to limit them to running a certain number of processes simultaneously, you can use parallelLimit() :

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

Read the async-q docs: https://github.com/dbushong/async-q/blob/master/READJSME.md

-2
source

All Articles