Compare commits
3 Commits
038b6cac33
...
178672ad0d
Author | SHA1 | Date |
---|---|---|
AJ ONeal | 178672ad0d | |
AJ ONeal | 9beae76631 | |
AJ ONeal | dd206891d5 |
127
batchasync.js
127
batchasync.js
|
@ -1,71 +1,70 @@
|
||||||
(function (exports) {
|
(function(exports) {
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
exports.batchAsync = function (limit, arr, doStuff) {
|
exports.batchAsync = function(limit, arr, doStuff) {
|
||||||
arr = arr.slice(0);
|
arr = arr.slice(0);
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
var total = arr.length;
|
var total = arr.length;
|
||||||
var active = 0;
|
var active = 0;
|
||||||
var results = [];
|
var results = [];
|
||||||
var error;
|
var error;
|
||||||
|
|
||||||
function doMoreStuff() {
|
function doMoreStuff() {
|
||||||
// Don't take on any more tasks if we've errored,
|
// Don't take on any more tasks if we've errored,
|
||||||
// or if too many are already in progress
|
// or if too many are already in progress
|
||||||
if (error || active > limit) {
|
if (error || active > limit) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no more tasks to start, return
|
// If there are no more tasks to start, return
|
||||||
if (!arr.length) {
|
if (!arr.length) {
|
||||||
// If everything is also *finished*, resolve
|
// If everything is also *finished*, resolve
|
||||||
if (active < 1) {
|
if (active < 1) {
|
||||||
resolve(results);
|
resolve(results);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to dequeue the task here so the index is correct
|
// We need to dequeue the task here so the index is correct
|
||||||
// (keep in mind we want to support sync and async)
|
// (keep in mind we want to support sync and async)
|
||||||
var index = total - arr.length;
|
var index = total - arr.length;
|
||||||
var task = arr.shift();
|
var task = arr.shift();
|
||||||
active += 1;
|
active += 1;
|
||||||
|
|
||||||
// Spawn another task immediately,
|
// Spawn another task immediately,
|
||||||
// which will be stopped if we're at the limit
|
// which will be stopped if we're at the limit
|
||||||
doMoreStuff();
|
doMoreStuff();
|
||||||
|
|
||||||
var p;
|
var p;
|
||||||
try {
|
try {
|
||||||
p = doStuff(task);
|
p = doStuff(task, index, arr);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// we need to handle, and bubble, synchronous errors
|
// we need to handle, and bubble, synchronous errors
|
||||||
error = e;
|
error = e;
|
||||||
reject(e);
|
reject(e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
// Do stuff and then decrease the active counter when done
|
// Do stuff and then decrease the active counter when done
|
||||||
// add support for sync by rapping in a promise
|
// add support for sync by rapping in a promise
|
||||||
Promise.resolve(p)
|
Promise.resolve(p)
|
||||||
.then(function(result) {
|
.then(function(result) {
|
||||||
if ('undefined' === typeof result) {
|
if ("undefined" === typeof result) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"result was 'undefined'. Please return 'null' to signal that you didn't just forget to return another promise."
|
"result was 'undefined'. Please return 'null' to signal that you didn't just forget to return another promise."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
active -= 1;
|
active -= 1;
|
||||||
results[index] = result;
|
results[index] = result;
|
||||||
})
|
})
|
||||||
.then(doMoreStuff)
|
.then(doMoreStuff)
|
||||||
.catch(function(e) {
|
.catch(function(e) {
|
||||||
// handle async errors
|
// handle async errors
|
||||||
error = e;
|
error = e;
|
||||||
reject(e);
|
reject(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
doMoreStuff();
|
doMoreStuff();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
})("undefined" !== typeof window ? window : module.exports);
|
||||||
}('undefined' !== typeof window ? window : module.exports));
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "batchasync",
|
||||||
|
"version": "1.0.3",
|
||||||
|
"lockfileVersion": 1
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "batchasync",
|
"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.",
|
"description": "Like forEachAsync, or Promise.all(), but handling a bounded number of items at any given time.",
|
||||||
"main": "batchasync.js",
|
"main": "batchasync.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
211
test.js
211
test.js
|
@ -1,110 +1,111 @@
|
||||||
(function (exports) {
|
(function(exports) {
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
var batchAsync = exports.batchAsync || require('./batchasync.js').batchAsync;
|
var batchAsync =
|
||||||
|
exports.batchAsync || require("./batchasync.js").batchAsync;
|
||||||
|
|
||||||
function testBatch() {
|
function testBatch() {
|
||||||
var timeouts = [100, 80, 20, 500, 50, 30, 200, 300];
|
var timeouts = [100, 80, 20, 500, 50, 30, 200, 300];
|
||||||
var tasks = timeouts.map(function(timeout, i) {
|
console.info(timeouts);
|
||||||
return function() {
|
var tasks = timeouts.map(function(timeout, i) {
|
||||||
return promiseTimeout(timeout).then(function() {
|
return function() {
|
||||||
console.log('task:', i, timeouts[i]);
|
return promiseTimeout(timeout).then(function() {
|
||||||
return i;
|
//console.log("task:", i, timeouts[i]);
|
||||||
});
|
return i + ":" + timeouts[i];
|
||||||
};
|
});
|
||||||
});
|
};
|
||||||
var len = tasks.length;
|
});
|
||||||
|
var len = tasks.length;
|
||||||
|
|
||||||
return batchAsync(4, tasks, function(task) {
|
return batchAsync(4, tasks, function(task) {
|
||||||
return task();
|
return task();
|
||||||
})
|
})
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
console.info('results:', results);
|
console.info("results:", results);
|
||||||
if (len !== results.length) {
|
if (len !== results.length) {
|
||||||
throw new Error('result set too small');
|
throw new Error("result set too small");
|
||||||
}
|
}
|
||||||
if (results.join(' ') !== results.sort().join(' ')) {
|
if (results.join(" ") !== results.sort().join(" ")) {
|
||||||
throw new Error('result set out-of-order');
|
throw new Error("result set out-of-order");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return batchAsync(4, [], 'not a function').then(function() {
|
return batchAsync(4, [], "not a function").then(function() {
|
||||||
console.info('Handled ZERO tasks correctly.');
|
console.info("Handled ZERO tasks correctly.");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return batchAsync(4, timeouts, function(x) {
|
return batchAsync(4, timeouts, function(x) {
|
||||||
return x;
|
return x;
|
||||||
}).then(function(results) {
|
}).then(function(results) {
|
||||||
if (results.join(' ') !== timeouts.join(' ')) {
|
if (results.join(" ") !== timeouts.join(" ")) {
|
||||||
console.error(results);
|
console.error(results);
|
||||||
throw new Error('sync result set out-of-order');
|
throw new Error("sync result set out-of-order");
|
||||||
}
|
}
|
||||||
console.info('Handled sync tasks correctly.');
|
console.info("Handled sync tasks correctly.");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return batchAsync(4, tasks, function(task) {
|
return batchAsync(4, tasks, function(task) {
|
||||||
if (0 === Math.floor(Math.random() * 2) % 2) {
|
if (0 === Math.floor(Math.random() * 2) % 2) {
|
||||||
throw new Error('any async error will do');
|
throw new Error("any async error will do");
|
||||||
}
|
}
|
||||||
return task();
|
return task();
|
||||||
})
|
})
|
||||||
.then(function(results) {
|
.then(function(results) {
|
||||||
console.log(results);
|
console.log(results);
|
||||||
var e = new Error('async rejection should not pass!');
|
var e = new Error("async rejection should not pass!");
|
||||||
e.FAIL = true;
|
e.FAIL = true;
|
||||||
throw e;
|
throw e;
|
||||||
})
|
})
|
||||||
.catch(function(e) {
|
.catch(function(e) {
|
||||||
if (e.FAIL) {
|
if (e.FAIL) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
console.info('Pass: Exception thrown when expected');
|
console.info("Pass: Exception thrown when expected");
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return batchAsync(4, timeouts, function() {
|
return batchAsync(4, timeouts, function() {
|
||||||
if (0 === Math.floor(Math.random() * 2) % 2) {
|
if (0 === Math.floor(Math.random() * 2) % 2) {
|
||||||
throw new Error('any sync error will do');
|
throw new Error("any sync error will do");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
.then(function(results) {
|
.then(function(/*results*/) {
|
||||||
var e = new Error('should not pass sync exception!');
|
var e = new Error("should not pass sync exception!");
|
||||||
e.FAIL = true;
|
e.FAIL = true;
|
||||||
throw e;
|
throw e;
|
||||||
})
|
})
|
||||||
.catch(function(e) {
|
.catch(function(e) {
|
||||||
if (e.FAIL) {
|
if (e.FAIL) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// wait for the tasks the error left dangling to print their message
|
// wait for the tasks the error left dangling to print their message
|
||||||
console.info('Pass: Promise rejected when expected');
|
console.info("Pass: Promise rejected when expected");
|
||||||
return promiseTimeout(1000);
|
return promiseTimeout(1000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function promiseTimeout(timeout) {
|
function promiseTimeout(timeout) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve) {
|
||||||
setTimeout(resolve, timeout);
|
setTimeout(resolve, timeout);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
testBatch()
|
testBatch()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.info('PROBABLY PASSED');
|
console.info("PROBABLY PASSED");
|
||||||
console.info(
|
console.info(
|
||||||
'We tested what could be tested without knowing Passed what could be tested Do the results make sense?'
|
"We tested what could be tested. Do the results make sense?"
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch(function(e) {
|
.catch(function(e) {
|
||||||
console.error('FAIL!');
|
console.error("FAIL!");
|
||||||
console.error(e);
|
console.error(e);
|
||||||
process.exit(500);
|
process.exit(500);
|
||||||
});
|
});
|
||||||
|
})("undefined" !== typeof window ? window : module.exports);
|
||||||
}('undefined' !== typeof window ? window : module.exports));
|
|
||||||
|
|
Loading…
Reference in New Issue