Like forEachAsync, or Promise.all(), but handling a bounded number of items at any given time.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

70 lines
2.5 KiB

(function(exports) {
"use strict";
exports.batchAsync = function(limit, arr, doStuff) {
arr = arr.slice(0);
return new Promise(function(resolve, reject) {
var total = arr.length;
var active = 0;
var results = [];
var error;
function doMoreStuff() {
// Don't take on any more tasks if we've errored,
// or if too many are already in progress
if (error || active > limit) {
return;
}
// If there are no more tasks to start, return
if (!arr.length) {
// If everything is also *finished*, resolve
if (active < 1) {
resolve(results);
}
return;
}
// We need to dequeue the task here so the index is correct
// (keep in mind we want to support sync and async)
var index = total - arr.length;
var task = arr.shift();
active += 1;
// Spawn another task immediately,
// which will be stopped if we're at the limit
doMoreStuff();
var p;
try {
p = doStuff(task, index, arr);
} catch (e) {
// we need to handle, and bubble, synchronous errors
error = e;
reject(e);
throw e;
}
// Do stuff and then decrease the active counter when done
// add support for sync by rapping in a promise
Promise.resolve(p)
.then(function(result) {
if ("undefined" === typeof result) {
throw new Error(
"result was 'undefined'. Please return 'null' to signal that you didn't just forget to return another promise."
);
}
active -= 1;
results[index] = result;
})
.then(doMoreStuff)
.catch(function(e) {
// handle async errors
error = e;
reject(e);
});
}
doMoreStuff();
});
};
})("undefined" !== typeof window ? window : module.exports);