summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Early <alexander.early@gmail.com>2016-04-04 11:41:42 -0700
committerAlex Early <alexander.early@gmail.com>2016-04-04 11:41:42 -0700
commit80197a31b33813ce42701cfc32a85c4ccc2ff5c7 (patch)
treeed4c1ea24c05bd1604907a55047ef00d18553173
parent283f5083f47c42f459bb07f20f48fda9f724fffa (diff)
parent53ca8e1756e432321928cc4fefb7b96ee685af96 (diff)
downloadasync-80197a31b33813ce42701cfc32a85c4ccc2ff5c7.tar.gz
Merge pull request #1095 from jtwebman/add-reflect
Add back reflect and reflectAll.
-rw-r--r--README.md81
-rw-r--r--lib/index.js6
-rw-r--r--lib/reflect.js29
-rw-r--r--lib/reflectAll.js7
-rwxr-xr-xtest/test-async.js125
5 files changed, 248 insertions, 0 deletions
diff --git a/README.md b/README.md
index 3009118..79ced0a 100644
--- a/README.md
+++ b/README.md
@@ -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){