Skip to content

Commit d1ef64c

Browse files
committed
Merge pull request #1038 from jorgebay/race-module
async.race module
2 parents a8c285b + 91a7e52 commit d1ef64c

File tree

4 files changed

+128
-0
lines changed

4 files changed

+128
-0
lines changed

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ Some functions are also available in the following forms:
221221
* [`retry`](#retry)
222222
* [`iterator`](#iterator)
223223
* [`times`](#times), `timesSeries`, `timesLimit`
224+
* [`race`](#race)
224225
225226
### Utils
226227
@@ -1655,6 +1656,46 @@ __Related__
16551656
16561657
---------------------------------------
16571658
1659+
<a name="race" />
1660+
### race(tasks, [callback])
1661+
1662+
Runs the `tasks` array of functions in parallel, without waiting until the
1663+
previous function has completed. Once any the `tasks` completed or pass an
1664+
error to its callback, the main `callback` is immediately called. It's
1665+
equivalent to `Promise.race()`.
1666+
1667+
__Arguments__
1668+
1669+
* `tasks` - An array containing functions to run. Each function is passed
1670+
a `callback(err, result)` which it must call on completion with an error `err`
1671+
(which can be `null`) and an optional `result` value.
1672+
* `callback(err, result)` - A callback to run once any of the
1673+
functions have completed. This function gets an error or result from the
1674+
first function that completed.
1675+
1676+
__Example__
1677+
1678+
```js
1679+
async.race([
1680+
function(callback){
1681+
setTimeout(function(){
1682+
callback(null, 'one');
1683+
}, 200);
1684+
},
1685+
function(callback){
1686+
setTimeout(function(){
1687+
callback(null, 'two');
1688+
}, 100);
1689+
}
1690+
],
1691+
// main callback
1692+
function(err, result){
1693+
// the result will be equal to 'two' as it finishes earlier
1694+
});
1695+
```
1696+
1697+
---------------------------------------
1698+
16581699
<a name="memoize"></a>
16591700
### memoize(fn, [hasher])
16601701

lib/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import parallel from './parallel';
4242
import parallelLimit from './parallelLimit';
4343
import priorityQueue from './priorityQueue';
4444
import queue from './queue';
45+
import race from './race';
4546
import reduce from './reduce';
4647
import reduceRight from './reduceRight';
4748
import reject from './reject';
@@ -106,6 +107,7 @@ export default {
106107
parallelLimit: parallelLimit,
107108
priorityQueue: priorityQueue,
108109
queue: queue,
110+
race: race,
109111
reduce: reduce,
110112
reduceRight: reduceRight,
111113
reject: reject,
@@ -188,6 +190,7 @@ export {
188190
parallelLimit as parallelLimit,
189191
priorityQueue as priorityQueue,
190192
queue as queue,
193+
race as race,
191194
reduce as reduce,
192195
reduceRight as reduceRight,
193196
reject as reject,

lib/race.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
3+
import isArray from 'lodash/isArray';
4+
import noop from 'lodash/noop';
5+
import once from 'lodash/once';
6+
7+
export default function race(tasks, cb) {
8+
cb = once(cb || noop);
9+
if (!isArray(tasks)) return cb(new TypeError('First argument to race must be an array of functions'));
10+
if (!tasks.length) return cb();
11+
for (let i = 0; i < tasks.length; i++) {
12+
tasks[i](cb);
13+
}
14+
}

mocha_test/race.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
var async = require('../lib');
2+
var assert = require('assert');
3+
4+
describe('race', function () {
5+
it('should call each function in parallel and callback with first result', function raceTest10(done) {
6+
var finished = 0;
7+
var tasks = [];
8+
function eachTest(i) {
9+
var index = i;
10+
return function (next) {
11+
finished++;
12+
next(null, index);
13+
};
14+
}
15+
for (var i = 0; i < 10; i++) {
16+
tasks[i] = eachTest(i);
17+
}
18+
async.race(tasks, function (err, result) {
19+
assert.ifError(err);
20+
//0 finished first
21+
assert.strictEqual(result, 0);
22+
assert.strictEqual(finished, 1);
23+
async.setImmediate(function () {
24+
assert.strictEqual(finished, 10);
25+
done();
26+
});
27+
});
28+
});
29+
it('should callback with the first error', function raceTest20(done) {
30+
var tasks = [];
31+
function eachTest(i) {
32+
var index = i;
33+
return function (next) {
34+
setTimeout(function () {
35+
next(new Error('ERR' + index));
36+
}, 50 - index * 2);
37+
};
38+
}
39+
for (var i = 0; i <= 5; i++) {
40+
tasks[i] = eachTest(i);
41+
}
42+
async.race(tasks, function (err, result) {
43+
assert.ok(err);
44+
assert.ok(err instanceof Error);
45+
assert.strictEqual(typeof result, 'undefined');
46+
assert.strictEqual(err.message, 'ERR5');
47+
done();
48+
});
49+
});
50+
it('should callback when task is empty', function raceTest30(done) {
51+
async.race([], function (err, result) {
52+
assert.ifError(err);
53+
assert.strictEqual(typeof result, 'undefined');
54+
done();
55+
});
56+
});
57+
it('should callback in error the task arg is not an Array', function raceTest40() {
58+
var errors = [];
59+
async.race(null, function (err) {
60+
errors.push(err);
61+
});
62+
async.race({}, function (err) {
63+
errors.push(err);
64+
});
65+
assert.strictEqual(errors.length, 2);
66+
assert.ok(errors[0] instanceof TypeError);
67+
assert.ok(errors[1] instanceof TypeError);
68+
});
69+
});
70+

0 commit comments

Comments
 (0)