Limitare la concorrenza della promise in corso

Sto cercando un wrapper di funzioni promettenti che possa limitare / limitare quando una determinata promise è in esecuzione in modo che solo un numero prestabilito di quella promise sia in esecuzione in un dato momento.

Nel caso in cui delayPromise non debba mai essere eseguito simultaneamente, dovrebbero essere tutti eseguiti uno alla volta in un ordine first-come-first-serve.

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

Qualche idea su come ottenere una coda come questa?

Ho una funzione di “rimbalzo” dal meraviglioso Benjamin Gruenbaum . Devo modificare questo per limitare una promise basata sulla propria esecuzione e non sul ritardo.

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

Non penso che ci siano librerie per farlo, ma in realtà è abbastanza semplice implementare te stesso:

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

Per più richieste simultanee diventa un po ‘più complicato, ma può anche essere fatto.

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

A proposito, potresti voler dare un'occhiata al modello degli attori e al CSP . Possono semplificare la gestione di queste cose, ci sono anche alcune librerie JS per loro.

Esempio

 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 

Ho lo stesso problema. Ho scritto una biblioteca per implementarla. Il codice è qui . Ho creato una coda per salvare tutte le promesse. Quando si promettono alcune promesse alla coda, le prime promesse in testa alla coda verrebbero visualizzate e in esecuzione. Una volta che una promise è stata fatta, la prossima promise in coda sarebbe anche spuntata e funzionante. Ancora e ancora, fino a quando la coda non ha Task . È ansible controllare il codice per i dettagli. Spero che questa libreria ti possa aiutare.

Usa il modulo con promise throttled:

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

Il modo classico di eseguire processi asincroni in serie consiste nell’utilizzare async.js e utilizzare async.series() . Se si preferisce il codice basato sulla promise, allora esiste una versione promise di async.js : async-q

Con async-q puoi ancora una volta usare la 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); }); 

L’esecuzione contemporanea di due di essi eseguirà a e b contemporaneamente ma all’interno di ciascuno saranno sequenziali:

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

Se si desidera eseguire b dopo a quindi inserirlo in .then() :

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

Se invece di eseguire ogni sequenza in modo sequenziale, si desidera limitare ciascuno a eseguire contemporaneamente un determinato numero di processi, quindi è ansible utilizzare parallelLimit() :

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

Leggi i documenti async-q: https://github.com/dbushong/async-q/blob/master/READJSME.md