Skip to content

Instantly share code, notes, and snippets.

@moodysalem
Created November 7, 2016 21:11
Show Gist options
  • Save moodysalem/08cbf799465b6f147adf282fac0dac13 to your computer and use it in GitHub Desktop.
Save moodysalem/08cbf799465b6f147adf282fac0dac13 to your computer and use it in GitHub Desktop.
JS function that calls a set of functions that generate promises (called generators) in batches and resolves when they have all completed
import _ from 'underscore';
/**
* Takes an array of generators, i.e. functions that return promises, and calls them such that there are only ever
* 5 requests that are waiting on responses. Returns a promise that resolves to all the resulting promises only after
* they have all been executed
*
* @param generators array of functions that
* @param batchSize max number of requests to execute at a time
* @param throttle how often the queue is checked for more requests to process
*/
export default function queuePromises(generators, { batchSize = 5, throttle = 100 } = {}) {
if (!_.isArray(generators)) {
return Promise.reject(new Error('Invalid argument generators: must be an array'));
}
if (!_.all(generators, fn => typeof fn == 'function')) {
return Promise.reject(new Error('Invalid set of generators: one or more were not functions'));
}
return new Promise(resolve => {
// this is the array we will shift items off of
const queued = [ ...generators ],
// this is the set of promises that have finished
done = [];
let inProgress = [];
// we will throttle how often we push from queued to in progress
const processMore = _.throttle(() => {
if (queued.length == 0) {
resolve(Promise.all(done.concat(inProgress)));
return;
}
// remove the generators we should trigger
const more = queued.splice(0, batchSize - inProgress.length);
// trigger the calls and add them to in progress
inProgress = inProgress.concat(
more.map(fn => {
// create the promise
const prom = fn();
// when it finishes, push it to the stack of done, remove it from inProgress
prom.finally(() => {
done.push(prom);
inProgress = _.without(inProgress, prom);
// add more to in progress
processMore();
});
return prom;
})
);
}, throttle);
processMore();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment