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

filter, reject, detect, some, every with error #774

Closed
wants to merge 14 commits into from
79 changes: 44 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ async.map(['file1','file2','file3'], fs.stat, function(err, results){
// results is now an array of stats for each file
});

async.filter(['file1','file2','file3'], fs.exists, function(results){
async.filter(['file1','file2','file3'], function(filePath, callback) {
fs.access(filePath, function(err) {
callback(filepath, !err)
});
}, function(err, results){
// results now equals an array of the existing files
});

Expand Down Expand Up @@ -393,25 +397,26 @@ __Related__
__Alias:__ `select`

Returns a new array of all the values in `arr` which pass an async truth test.
_The callback for each `iteratee` call only accepts a single argument of `true` or
`false`; it does not accept an error argument first!_ This is in-line with the
way node libraries work with truth tests like `fs.exists`. This operation is
performed in parallel, but the results array will be in the same order as the
original.
This operation is performed in parallel,
but the results array will be in the same order as the original.

__Arguments__

* `arr` - An array to iterate over.
* `iteratee(item, callback)` - A truth test to apply to each item in `arr`.
The `iteratee` is passed a `callback(truthValue)`, which must be called with a
The `iteratee` is passed a `callback(err, truthValue)`, which must be called with a
boolean argument once it has completed.
* `callback(results)` - *Optional* A callback which is called after all the `iteratee`
* `callback(err, results)` - *Optional* A callback which is called after all the `iteratee`
functions have finished.

__Example__

```js
async.filter(['file1','file2','file3'], fs.exists, function(results){
async.filter(['file1','file2','file3'], function(filePath, callback) {
fs.access(filePath, function(err) {
callback(filepath, !err)
});
}, function(err, results){
// results now equals an array of the existing files
});
```
Expand Down Expand Up @@ -500,17 +505,21 @@ __Arguments__

* `arr` - An array to iterate over.
* `iteratee(item, callback)` - A truth test to apply to each item in `arr`.
The iteratee is passed a `callback(truthValue)` which must be called with a
boolean argument once it has completed. **Note: this callback does not take an error as its first argument.**
* `callback(result)` - *Optional* A callback which is called as soon as any iteratee returns
The iteratee is passed a `callback(err, truthValue)` which must be called with a
boolean argument once it has completed.
* `callback(err, result)` - *Optional* A callback which is called as soon as any iteratee returns
`true`, or after all the `iteratee` functions have finished. Result will be
the first item in the array that passes the truth test (iteratee) or the
value `undefined` if none passed. **Note: this callback does not take an error as its first argument.**
value `undefined` if none passed.

__Example__

```js
async.detect(['file1','file2','file3'], fs.exists, function(result){
async.detect(['file1','file2','file3'], function(filePath, callback) {
fs.access(filePath, function(err) {
callback(filepath, !err)
});
}, function(err, result){
// result now equals the first file in the list that exists
});
```
Expand Down Expand Up @@ -579,26 +588,26 @@ async.sortBy([1,9,3,5], function(x, callback){
__Alias:__ `any`

Returns `true` if at least one element in the `arr` satisfies an async test.
_The callback for each iteratee call only accepts a single argument of `true` or
`false`; it does not accept an error argument first!_ This is in-line with the
way node libraries work with truth tests like `fs.exists`. Once any iteratee
call returns `true`, the main `callback` is immediately called.
If any iteratee call returns `true`, the main `callback` is immediately called.

__Arguments__

* `arr` - An array to iterate over.
* `iteratee(item, callback)` - A truth test to apply to each item in the array
in parallel. The iteratee is passed a `callback(truthValue)`` which must be
called with a boolean argument once it has completed.
* `callback(result)` - *Optional* A callback which is called as soon as any iteratee returns
* `callback(err, result)` - *Optional* A callback which is called as soon as any iteratee returns
`true`, or after all the iteratee functions have finished. Result will be
either `true` or `false` depending on the values of the async tests.

**Note: the callbacks do not take an error as their first argument.**
__Example__

```js
async.some(['file1','file2','file3'], fs.exists, function(result){
async.some(['file1','file2','file3'], function(filePath, callback) {
fs.access(filePath, function(err) {
callback(filepath, !err)
});
}, function(err, result){
// if result is true then at least one of the files exists
});
```
Expand All @@ -615,26 +624,26 @@ __Related__
__Alias:__ `all`

Returns `true` if every element in `arr` satisfies an async test.
_The callback for each `iteratee` call only accepts a single argument of `true` or
`false`; it does not accept an error argument first!_ This is in-line with the
way node libraries work with truth tests like `fs.exists`.
If any iteratee call returns `false`, the main `callback` is immediately called.

__Arguments__

* `arr` - An array to iterate over.
* `iteratee(item, callback)` - A truth test to apply to each item in the array
in parallel. The iteratee is passed a `callback(truthValue)` which must be
in parallel. The iteratee is passed a `callback(err, truthValue)` which must be
called with a boolean argument once it has completed.
* `callback(result)` - *Optional* A callback which is called as soon as any iteratee returns
`false`, or after all the iteratee functions have finished. Result will be
either `true` or `false` depending on the values of the async tests.

**Note: the callbacks do not take an error as their first argument.**
* `callback(err, result)` - *Optional* A callback which is called after all the `iteratee`
functions have finished. Result will be either `true` or `false` depending on
the values of the async tests.

__Example__

```js
async.every(['file1','file2','file3'], fs.exists, function(result){
async.every(['file1','file2','file3'], function(filePath, callback) {
fs.access(filePath, function(err) {
callback(filepath, !err)
});
}, function(err, result){
// if result is true then every file exists
});
```
Expand Down Expand Up @@ -1446,7 +1455,7 @@ __Arguments__
* `opts` - Can be either an object with `times` and `interval` or a number.
* `times` - The number of attempts to make before giving up. The default is `5`.
* `interval` - The time to wait between retries, in milliseconds. The default is `0`.
* If `opts` is a number, the number specifies the number of times to retry, with the default interval of `0`.
* If `opts` is a number, the number specifies the number of times to retry, with the default interval of `0`.
* `task(callback, results)` - A function which receives two arguments: (1) a `callback(err, result)`
which must be called when finished, passing `err` (which can be `null`) and the `result` of
the function's execution, and (2) a `results` object, containing the results of
Expand All @@ -1464,14 +1473,14 @@ async.retry(3, apiMethod, function(err, result) {
```

```js
// try calling apiMethod 3 times, waiting 200 ms between each retry
// try calling apiMethod 3 times, waiting 200 ms between each retry
async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {
// do something with the result
});
```

```js
// try calling apiMethod the default 5 times no delay between each retry
// try calling apiMethod the default 5 times no delay between each retry
async.retry(apiMethod, function(err, result) {
// do something with the result
});
Expand Down Expand Up @@ -1792,7 +1801,7 @@ async.waterfall([
return db.model.create(contents);
}),
function (model, next) {
// `model` is the instantiated model object.
// `model` is the instantiated model object.
// If there was an error, this function would be skipped.
}
], callback)
Expand Down
60 changes: 42 additions & 18 deletions lib/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -404,18 +404,26 @@
function _filter(eachfn, arr, iterator, callback) {
var results = [];
eachfn(arr, function (x, index, callback) {
iterator(x, function (v) {
if (v) {
results.push({index: index, value: x});
iterator(x, function (err, v) {
if (err) {
callback(err);
} else {
if (v) {
results.push({index: index, value: x});
}
callback();
}
callback();
});
}, function () {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
}, function (err) {
if (err) {
callback(err);
} else {
callback(null, _map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
}
});
}

Expand All @@ -430,26 +438,42 @@

function _reject(eachfn, arr, iterator, callback) {
_filter(eachfn, arr, function(value, cb) {
iterator(value, function(v) {
cb(!v);
iterator(value, function(err, v) {
if (err) {
cb(err);
} else {
cb(null, !v);
}
});
}, callback);
}

async.reject = doParallel(_reject);
async.rejectLimit = doParallelLimit(_reject);
async.rejectSeries = doSeries(_reject);

function _createTester(eachfn, check, getResult) {
return function(arr, limit, iterator, cb) {
function done() {
if (cb) cb(getResult(false, void 0));
function done(err) {
if (cb) {
if (err) {
cb(err);
} else {
cb(null, getResult(false, void 0));
}
}
}
function iteratee(x, _, callback) {
if (!cb) return callback();
iterator(x, function (v) {
if (cb && check(v)) {
cb(getResult(true, x));
cb = iterator = false;
iterator(x, function (err, v) {
if (cb) {
if (err) {
cb(err);
cb = iterator = false;
} else if (check(v)) {
cb(null, getResult(true, x));
cb = iterator = false;
}
}
callback();
});
Expand Down
Loading