Compare commits

..

3 Commits

Author SHA1 Message Date
AJ ONeal 178672ad0d v1.0.3: use index as well 2019-11-25 16:05:46 -07:00
AJ ONeal 9beae76631 make Prettier 2019-11-25 15:43:58 -07:00
AJ ONeal dd206891d5 make Prettier 2019-11-25 15:38:55 -07:00
4 changed files with 175 additions and 170 deletions

View File

@ -1,71 +1,70 @@
(function (exports) {
'use strict';
(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;
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;
}
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;
}
// 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;
// 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();
// Spawn another task immediately,
// which will be stopped if we're at the limit
doMoreStuff();
var p;
try {
p = doStuff(task);
} 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);
});
}
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));
doMoreStuff();
});
};
})("undefined" !== typeof window ? window : module.exports);

5
package-lock.json generated Normal file
View File

@ -0,0 +1,5 @@
{
"name": "batchasync",
"version": "1.0.3",
"lockfileVersion": 1
}

View File

@ -1,6 +1,6 @@
{
"name": "batchasync",
"version": "1.0.2",
"version": "1.0.3",
"description": "Like forEachAsync, or Promise.all(), but handling a bounded number of items at any given time.",
"main": "batchasync.js",
"scripts": {

211
test.js
View File

@ -1,110 +1,111 @@
(function (exports) {
'use strict';
(function(exports) {
"use strict";
var batchAsync = exports.batchAsync || require('./batchasync.js').batchAsync;
var batchAsync =
exports.batchAsync || require("./batchasync.js").batchAsync;
function testBatch() {
var timeouts = [100, 80, 20, 500, 50, 30, 200, 300];
var tasks = timeouts.map(function(timeout, i) {
return function() {
return promiseTimeout(timeout).then(function() {
console.log('task:', i, timeouts[i]);
return i;
});
};
});
var len = tasks.length;
function testBatch() {
var timeouts = [100, 80, 20, 500, 50, 30, 200, 300];
console.info(timeouts);
var tasks = timeouts.map(function(timeout, i) {
return function() {
return promiseTimeout(timeout).then(function() {
//console.log("task:", i, timeouts[i]);
return i + ":" + timeouts[i];
});
};
});
var len = tasks.length;
return batchAsync(4, tasks, function(task) {
return task();
})
.then(function(results) {
console.info('results:', results);
if (len !== results.length) {
throw new Error('result set too small');
}
if (results.join(' ') !== results.sort().join(' ')) {
throw new Error('result set out-of-order');
}
})
.then(function() {
return batchAsync(4, [], 'not a function').then(function() {
console.info('Handled ZERO tasks correctly.');
});
})
.then(function() {
return batchAsync(4, timeouts, function(x) {
return x;
}).then(function(results) {
if (results.join(' ') !== timeouts.join(' ')) {
console.error(results);
throw new Error('sync result set out-of-order');
}
console.info('Handled sync tasks correctly.');
});
})
.then(function() {
return batchAsync(4, tasks, function(task) {
if (0 === Math.floor(Math.random() * 2) % 2) {
throw new Error('any async error will do');
}
return task();
})
.then(function(results) {
console.log(results);
var e = new Error('async rejection should not pass!');
e.FAIL = true;
throw e;
})
.catch(function(e) {
if (e.FAIL) {
throw e;
}
console.info('Pass: Exception thrown when expected');
});
})
.then(function() {
return batchAsync(4, timeouts, function() {
if (0 === Math.floor(Math.random() * 2) % 2) {
throw new Error('any sync error will do');
}
return null;
})
.then(function(results) {
var e = new Error('should not pass sync exception!');
e.FAIL = true;
throw e;
})
.catch(function(e) {
if (e.FAIL) {
throw e;
}
})
.then(function() {
// wait for the tasks the error left dangling to print their message
console.info('Pass: Promise rejected when expected');
return promiseTimeout(1000);
});
});
}
return batchAsync(4, tasks, function(task) {
return task();
})
.then(function(results) {
console.info("results:", results);
if (len !== results.length) {
throw new Error("result set too small");
}
if (results.join(" ") !== results.sort().join(" ")) {
throw new Error("result set out-of-order");
}
})
.then(function() {
return batchAsync(4, [], "not a function").then(function() {
console.info("Handled ZERO tasks correctly.");
});
})
.then(function() {
return batchAsync(4, timeouts, function(x) {
return x;
}).then(function(results) {
if (results.join(" ") !== timeouts.join(" ")) {
console.error(results);
throw new Error("sync result set out-of-order");
}
console.info("Handled sync tasks correctly.");
});
})
.then(function() {
return batchAsync(4, tasks, function(task) {
if (0 === Math.floor(Math.random() * 2) % 2) {
throw new Error("any async error will do");
}
return task();
})
.then(function(results) {
console.log(results);
var e = new Error("async rejection should not pass!");
e.FAIL = true;
throw e;
})
.catch(function(e) {
if (e.FAIL) {
throw e;
}
console.info("Pass: Exception thrown when expected");
});
})
.then(function() {
return batchAsync(4, timeouts, function() {
if (0 === Math.floor(Math.random() * 2) % 2) {
throw new Error("any sync error will do");
}
return null;
})
.then(function(/*results*/) {
var e = new Error("should not pass sync exception!");
e.FAIL = true;
throw e;
})
.catch(function(e) {
if (e.FAIL) {
throw e;
}
})
.then(function() {
// wait for the tasks the error left dangling to print their message
console.info("Pass: Promise rejected when expected");
return promiseTimeout(1000);
});
});
}
function promiseTimeout(timeout) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, timeout);
});
}
function promiseTimeout(timeout) {
return new Promise(function(resolve) {
setTimeout(resolve, timeout);
});
}
testBatch()
.then(function() {
console.info('PROBABLY PASSED');
console.info(
'We tested what could be tested without knowing Passed what could be tested Do the results make sense?'
);
})
.catch(function(e) {
console.error('FAIL!');
console.error(e);
process.exit(500);
});
}('undefined' !== typeof window ? window : module.exports));
testBatch()
.then(function() {
console.info("PROBABLY PASSED");
console.info(
"We tested what could be tested. Do the results make sense?"
);
})
.catch(function(e) {
console.error("FAIL!");
console.error(e);
process.exit(500);
});
})("undefined" !== typeof window ? window : module.exports);