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 eachIndex/forEachIndex function with tests #264

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/node_modules
/dist
/.idea
46 changes: 44 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ So far its been tested in IE6, IE7, IE8, FF3.6 and Chrome 5. Usage:
### Collections

* [each](#each)
* [eachIndex](#eachIndex)
* [map](#map)
* [filter](#filter)
* [reject](#reject)
Expand Down Expand Up @@ -131,7 +132,7 @@ __Arguments__
* arr - An array to iterate over.
* iterator(item, callback) - A function to apply to each item in the array.
The iterator is passed a callback(err) which must be called once it has
completed. If no error has occured, the callback should be run without
completed. If no error has occurred, the callback should be run without
arguments or with an explicit null argument.
* callback(err) - A callback which is called after all the iterator functions
have finished, or an error has occurred.
Expand All @@ -147,6 +148,47 @@ async.each(openFiles, saveFile, function(err){
});
```

<a name="forEachIndex" />
<a name="eachIndex" />
### eachIndex(arr, iterator, callback)

Just like `each`, applies an iterator function to each item in an array,
in parallel. The iterator is called with an item from the list, the position
an item is at in the supplied array, and a callback for when it has finished.
If the iterator passes an error to this callback, the main callback for the
`eachIndex` function is immediately called with the error.

Note, that since this function applies the iterator to each item in parallel
there is no guarantee that the iterator functions will complete in order.

__Arguments__

* arr - An array to iterate over.
* iterator(item, index, callback) - A function to apply to each item in
the array. The iterator is passed an `index` position of the item in the
array. Useful when it is necessary to distinguish each item based on its
position in the array. Also the iterator is passed a `callback(err)`
which must be called once it has completed. If no error has occurred,
the callback should be run without arguments or with an explicit null
argument.
* callback(err) - A callback which is called after all the iterator functions
have finished, or an error has occurred.

__Example__

```js
var itemsArr = ['apple', 'banana', 'orange'];

function iterator(val, index, callback) {
// do something with `val` based on its `index`,
// then call `callback`.
}

async.eachIndex(itemsArr, iterator, function(err){
// if any of the iterators produced an error, err would equal that error
});
```

---------------------------------------

<a name="forEachSeries" />
Expand Down Expand Up @@ -177,7 +219,7 @@ __Arguments__
* limit - The maximum number of iterators to run at any time.
* iterator(item, callback) - A function to apply to each item in the array.
The iterator is passed a callback(err) which must be called once it has
completed. If no error has occured, the callback should be run without
completed. If no error has occurred, the callback should be run without
arguments or with an explicit null argument.
* callback(err) - A callback which is called after all the iterator functions
have finished, or an error has occurred.
Expand Down
23 changes: 23 additions & 0 deletions lib/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,29 @@
};
async.forEach = async.each;

async.eachIndex = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
_each(arr, function (x, ix) {
iterator(x, ix, only_once(function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed >= arr.length) {
callback(null);
}
}
}));
});
};
async.forEachIndex = async.eachIndex;

async.eachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
Expand Down
63 changes: 63 additions & 0 deletions test/test-async.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ function eachIterator(args, x, callback) {
}, x*25);
}

function eachIndexIterator(args, x, ix, callback) {
setTimeout(function(){
args.push(x);
callback();
}, x*25);
}

function mapIterator(call_order, x, callback) {
setTimeout(function(){
call_order.push(x);
Expand All @@ -43,6 +50,12 @@ function eachNoCallbackIterator(test, x, callback) {
test.done();
}

function eachIndexNoCallbackIterator(test, x, ix, callback) {
test.equal(x, 1);
callback();
test.done();
}

function getFunctionsObject(call_order) {
return {
one: function(callback){
Expand Down Expand Up @@ -824,6 +837,56 @@ exports['forEach alias'] = function (test) {
test.done();
};

exports['eachIndex'] = function(test){
var args = [];
async.eachIndex([1,3,2], eachIndexIterator.bind(this, args), function(err){
test.same(args, [1,2,3]);
test.done();
});
};

exports['eachIndex extra callback'] = function(test){
var count = 0;
async.eachIndex([1,3,2], function(val, index, callback) {
count++;
callback();
test.throws(callback);
if (count == 3) {
test.done();
}
});
};

exports['eachIndex empty array'] = function(test){
test.expect(1);
async.eachIndex([], function(x, ix, callback){
test.ok(false, 'iterator should not be called');
callback();
}, function(err){
test.ok(true, 'should call callback');
});
setTimeout(test.done, 25);
};

exports['eachIndex error'] = function(test){
test.expect(1);
async.eachIndex([1,2,3], function(x, ix, callback){
callback('error');
}, function(err){
test.equals(err, 'error');
});
setTimeout(test.done, 50);
};

exports['eachIndex no callback'] = function(test){
async.eachIndex([1], eachIndexNoCallbackIterator.bind(this, test));
};

exports['forEachIndex alias'] = function (test) {
test.strictEqual(async.eachIndex, async.forEachIndex);
test.done();
};

exports['eachSeries'] = function(test){
var args = [];
async.eachSeries([1,3,2], eachIterator.bind(this, args), function(err){
Expand Down