Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add async.tryEach #1365

Merged
merged 1 commit into from Apr 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/index.js
Expand Up @@ -89,6 +89,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 @@ -163,6 +164,7 @@ export default {
timesLimit: timesLimit,
timesSeries: timesSeries,
transform: transform,
tryEach: tryEach,
unmemoize: unmemoize,
until: until,
waterfall: waterfall,
Expand Down Expand Up @@ -255,6 +257,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();
});
});
});