71 linhas
2.5 KiB
JavaScript
71 linhas
2.5 KiB
JavaScript
(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);
|