Skip to content

Commit

Permalink
Merge pull request #1365 from alFReD-NSH/try
Browse files Browse the repository at this point in the history
Add async.tryEach
  • Loading branch information
aearly committed Apr 7, 2017
2 parents b3679d5 + 465cfe8 commit 7aa90f3
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/index.js
Expand Up @@ -134,6 +134,7 @@ import times from './times';
import timesLimit from './timesLimit';
import timesSeries from './timesSeries';
import transform from './transform';
import tryEach from './tryEach';
import unmemoize from './unmemoize';
import until from './until';
import waterfall from './waterfall';
Expand Down Expand Up @@ -211,6 +212,7 @@ export default {
timesLimit: timesLimit,
timesSeries: timesSeries,
transform: transform,
tryEach: tryEach,
unmemoize: unmemoize,
until: until,
waterfall: waterfall,
Expand Down Expand Up @@ -306,6 +308,7 @@ export {
timesLimit as timesLimit,
timesSeries as timesSeries,
transform as transform,
tryEach as tryEach,
unmemoize as unmemoize,
until as until,
waterfall as waterfall,
Expand Down
58 changes: 58 additions & 0 deletions lib/tryEach.js
@@ -0,0 +1,58 @@
import noop from 'lodash/noop';
import eachSeries from './eachSeries';
import rest from './internal/rest';

/**
* It runs each task in series but stops whenever any of the functions were
* successful. If one of the tasks were successful, the `callback` will be
* passed the result of the successful task. If all tasks fail, the callback
* will be passed the error and result (if any) of the final attempt.
*
* @name tryEach
* @static
* @memberOf module:ControlFlow
* @method
* @category Control Flow
* @param {Array|Iterable|Object} tasks - A collection containing functions to
* run, each function is passed a `callback(err, result)` it must call on
* completion with an error `err` (which can be `null`) and an optional `result`
* value.
* @param {Function} [callback] - An optional callback which is called when one
* of the tasks has succeeded, or all have failed. It receives the `err` and
* `result` arguments of the last attempt at completing the `task`. Invoked with
* (err, results).
* @example
* async.try([
* function getDataFromFirstWebsite(callback) {
* // Try getting the data from the first website
* callback(err, data);
* },
* function getDataFromSecondWebsite(callback) {
* // First website failed,
* // Try getting the data from the backup website
* callback(err, data);
* }
* ],
* // optional callback
* function(err, results) {
* Now do something with the data.
* });
*
*/
export default function tryEach(tasks, callback) {
var error = null;
var result;
callback = callback || noop;
eachSeries(tasks, function(task, callback) {
task(rest(function (err, args) {
if (args.length <= 1) {
args = args[0];
}
error = err;
result = args;
callback(!err);
}));
}, function () {
callback(error, result);
});
}
86 changes: 86 additions & 0 deletions mocha_test/tryEach.js
@@ -0,0 +1,86 @@
var async = require('../lib');
var expect = require('chai').expect;
var assert = require('assert');

describe('try', function () {
it('no callback', function () {
async.tryEach([]);
});
it('empty', function (done) {
async.tryEach([], function (err, results) {
expect(err).to.equal(null);
expect(results).to.eql(undefined);
done();
});
});
it('one task, multiple results', function (done) {
var RESULTS = ['something', 'something2'];
async.tryEach([
function (callback) {
callback(null, RESULTS[0], RESULTS[1]);
}
], function (err, results) {
expect(err).to.equal(null);
expect(results).to.eql(RESULTS);
done();
});
});
it('one task', function (done) {
var RESULT = 'something';
async.tryEach([
function (callback) {
callback(null, RESULT);
}
], function (err, results) {
expect(err).to.equal(null);
expect(results).to.eql(RESULT);
done();
});
});
it('two tasks, one failing', function (done) {
var RESULT = 'something';
async.tryEach([
function (callback) {
callback(new Error('Failure'), {});
},
function (callback) {
callback(null, RESULT);
}
], function (err, results) {
expect(err).to.equal(null);
expect(results).to.eql(RESULT);
done();
});
});
it('two tasks, both failing', function (done) {
var ERROR_RESULT = new Error('Failure2');
async.tryEach([
function (callback) {
callback(new Error('Should not stop here'));
},
function (callback) {
callback(ERROR_RESULT);
}
], function (err, results) {
expect(err).to.equal(ERROR_RESULT);
expect(results).to.eql(undefined);
done();
});
});
it('two tasks, non failing', function (done) {
var RESULT = 'something';
async.tryEach([
function (callback) {
callback(null, RESULT);
},
function () {
assert.fail('Should not been called');
},
], function (err, results) {
expect(err).to.equal(null);
expect(results).to.eql(RESULT);
done();
});
});
});

0 comments on commit 7aa90f3

Please sign in to comment.