diff options
author | Alex Early <alexander.early@gmail.com> | 2016-04-04 11:41:42 -0700 |
---|---|---|
committer | Alex Early <alexander.early@gmail.com> | 2016-04-04 11:41:42 -0700 |
commit | 80197a31b33813ce42701cfc32a85c4ccc2ff5c7 (patch) | |
tree | ed4c1ea24c05bd1604907a55047ef00d18553173 | |
parent | 283f5083f47c42f459bb07f20f48fda9f724fffa (diff) | |
parent | 53ca8e1756e432321928cc4fefb7b96ee685af96 (diff) | |
download | async-80197a31b33813ce42701cfc32a85c4ccc2ff5c7.tar.gz |
Merge pull request #1095 from jtwebman/add-reflect
Add back reflect and reflectAll.
-rw-r--r-- | README.md | 81 | ||||
-rw-r--r-- | lib/index.js | 6 | ||||
-rw-r--r-- | lib/reflect.js | 29 | ||||
-rw-r--r-- | lib/reflectAll.js | 7 | ||||
-rwxr-xr-x | test/test-async.js | 125 |
5 files changed, 248 insertions, 0 deletions
@@ -264,6 +264,8 @@ Some functions are also available in the following forms: * [`dir`](#dir) * [`noConflict`](#noConflict) * [`timeout`](#timeout) +* [`reflect`](#reflect) +* [`reflectAll`](#reflectAll) ## Collections @@ -2095,3 +2097,82 @@ async.timeout(function(callback) { doAsyncTask(callback); }, 1000); ``` + +--------------------------------------- + +<a name="reflect"></a> +### reflect(function) + +Wraps the function in another function that always returns data even when it errors. +The object returns ether has a property of error or value. + +__Arguments__ + +* `function` - The function you want to wrap + +__Example__ + +```js +async.parallel([ + async.reflect(function(callback){ + // do some stuff ... + callback(null, 'one'); + }), + async.reflect(function(callback){ + // do some more stuff but error ... + callback('bad stuff happened'); + }), + async.reflect(function(callback){ + // do some more stuff ... + callback(null, 'two'); + }) +], +// optional callback +function(err, results){ + // values + // results[0].value = 'one' + // results[1].error = 'bad stuff happened' + // results[2].value = 'two' +}); +``` + +--------------------------------------- + +<a name="reflectAll"></a> +### reflectAll() + +A helper function that wraps an array of functions with reflect. + +__Arguments__ + +* `tasks` - The array of functions to wrap in reflect. + +__Example__ + +```javascript +let tasks = [ + function(callback){ + setTimeout(function(){ + callback(null, 'one'); + }, 200); + }, + function(callback){ + // do some more stuff but error ... + callback(new Error('bad stuff happened')); + } + function(callback){ + setTimeout(function(){ + callback(null, 'two'); + }, 100); + } +]; + +async.parallel(async.reflectAll(tasks), +// optional callback +function(err, results){ + // values + // results[0].value = 'one' + // results[1].error = Error('bad stuff happened') + // results[2].value = 'two' +}); +``` diff --git a/lib/index.js b/lib/index.js index e3eb48d..6832662 100644 --- a/lib/index.js +++ b/lib/index.js @@ -47,7 +47,9 @@ import queue from './queue'; import race from './race'; import reduce from './reduce'; import reduceRight from './reduceRight'; +import reflect from './reflect'; import reject from './reject'; +import reflectAll from './reflectAll'; import rejectLimit from './rejectLimit'; import rejectSeries from './rejectSeries'; import retry from './retry'; @@ -117,6 +119,8 @@ export default { race: race, reduce: reduce, reduceRight: reduceRight, + reflect: reflect, + reflectAll: reflectAll, reject: reject, rejectLimit: rejectLimit, rejectSeries: rejectSeries, @@ -205,6 +209,8 @@ export { race as race, reduce as reduce, reduceRight as reduceRight, + reflect as reflect, + reflectAll as reflectAll, reject as reject, rejectLimit as rejectLimit, rejectSeries as rejectSeries, diff --git a/lib/reflect.js b/lib/reflect.js new file mode 100644 index 0000000..53cfa44 --- /dev/null +++ b/lib/reflect.js @@ -0,0 +1,29 @@ +'use strict'; + +export default function reflect(fn) { + return function reflectOn() { + var args = Array.prototype.slice.call(arguments); + var reflectCallback = args.pop(); + + args.push(function callback(err) { + if (err) { + reflectCallback(null, { + error: err + }); + } else { + var cbArgs = Array.prototype.slice.call(arguments, 1); + var value = null; + if (cbArgs.length === 1) { + value = cbArgs[0]; + } else if (cbArgs.length > 1) { + value = cbArgs; + } + reflectCallback(null, { + value: value + }); + } + }); + + return fn.apply(this, args); + }; +} diff --git a/lib/reflectAll.js b/lib/reflectAll.js new file mode 100644 index 0000000..c4ecd9f --- /dev/null +++ b/lib/reflectAll.js @@ -0,0 +1,7 @@ +'use strict'; + +import reflect from './reflect'; + +export default function reflectAll(tasks) { + return tasks.map(reflect); +} diff --git a/test/test-async.js b/test/test-async.js index 6e11b5a..6831ac2 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -491,6 +491,29 @@ exports['parallel call in another context'] = function(test) { vm.runInNewContext(fn, sandbox); }; +exports['parallel error with reflect'] = function(test){ + async.parallel([ + async.reflect(function(callback){ + callback('error', 1); + }), + async.reflect(function(callback){ + callback('error2', 2); + }), + async.reflect(function(callback){ + callback(null, 2); + }) + ], + function(err, results){ + test.ok(err === null, err + " passed instead of 'null'"); + test.same(results, [ + { error: 'error' }, + { error: 'error2' }, + { value: 2 } + ]); + test.done(); + }); +}; + exports['parallel does not continue replenishing after error'] = function (test) { var started = 0; var arr = [ @@ -558,6 +581,40 @@ exports['series'] = { }); }, + 'with reflect': function(test){ + var call_order = []; + async.series([ + async.reflect(function(callback){ + setTimeout(function(){ + call_order.push(1); + callback(null, 1); + }, 25); + }), + async.reflect(function(callback){ + setTimeout(function(){ + call_order.push(2); + callback(null, 2); + }, 50); + }), + async.reflect(function(callback){ + setTimeout(function(){ + call_order.push(3); + callback(null, 3,3); + }, 15); + }) + ], + function(err, results){ + test.ok(err === null, err + " passed instead of 'null'"); + test.deepEqual(results, [ + { value: 1 }, + { value: 2 }, + { value: [3,3] } + ]); + test.same(call_order, [1,2,3]); + test.done(); + }); +}, + 'empty array': function(test){ async.series([], function(err, results){ test.equals(err, null); @@ -583,6 +640,30 @@ exports['series'] = { setTimeout(test.done, 100); }, + 'error with reflect': function(test){ + test.expect(2); + async.series([ + async.reflect(function(callback){ + callback('error', 1); + }), + async.reflect(function(callback){ + callback('error2', 2); + }), + async.reflect(function(callback){ + callback(null, 1); + }) + ], + function(err, results){ + test.ok(err === null, err + " passed instead of 'null'"); + test.deepEqual(results, [ + { error: 'error' }, + { error: 'error2' }, + { value: 1 } + ]); + test.done(); + }); +}, + 'no callback': function(test){ async.series([ function(callback){callback();}, @@ -1334,6 +1415,50 @@ exports['map'] = { }); }, + 'with reflect': function(test){ + var call_order = []; + async.map([1,3,2], async.reflect(function(item, cb) { + setTimeout(function(){ + call_order.push(item); + cb(null, item*2); + }, item*25); + }), function(err, results){ + test.ok(err === null, err + " passed instead of 'null'"); + test.same(call_order, [1,2,3]); + test.same(results, [ + { value: 2 }, + { value: 6 }, + { value: 4 } + ]); + test.done(); + }); +}, + + 'error with reflect': function(test){ + var call_order = []; + async.map([-1,1,3,2], async.reflect(function(item, cb) { + setTimeout(function(){ + call_order.push(item); + if (item < 0) { + cb('number less then zero'); + } else { + cb(null, item*2); + } + + }, item*25); + }), function(err, results){ + test.ok(err === null, err + " passed instead of 'null'"); + test.same(call_order, [-1,1,2,3]); + test.same(results, [ + { error: 'number less then zero' }, + { value: 2 }, + { value: 6 }, + { value: 4 } + ]); + test.done(); + }); +}, + 'map original untouched': function(test){ var a = [1,2,3]; async.map(a, function(x, callback){ |