Skip to content

Commit

Permalink
ensure map and filter results stay in the same order when processing …
Browse files Browse the repository at this point in the history
…in parallel
  • Loading branch information
Caolan McMahon committed Jun 9, 2010
1 parent ea4c476 commit a57d319
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 23 deletions.
17 changes: 7 additions & 10 deletions README.md
Expand Up @@ -99,9 +99,8 @@ error to this callback, the main callback for the map function is immediately
called with the error. called with the error.


Note, that since this function applies the iterator to each item in parallel 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. The there is no guarantee that the iterator functions will complete in order, however
results array can be in a different order to the source array. If you need the the results array will be in the same order as the original array.
order to be the same, then use mapSeries instead.


__Arguments__ __Arguments__


Expand All @@ -123,8 +122,7 @@ __Example__


The same as map only the iterator is applied to each item in the array in The same as map only the iterator is applied to each item in the array in
series. The next iterator is only called once the current one has completed series. The next iterator is only called once the current one has completed
processing, meaning the results array will be in the same order as the processing. The results array will be in the same order as the original.
original.




### filter(arr, iterator, callback) ### filter(arr, iterator, callback)
Expand All @@ -133,7 +131,7 @@ Returns a new array of all the values which pass an async truth test.
_The callback for each iterator call only accepts a single argument of true or _The callback for each iterator call only accepts a single argument of true or
false, it does not accept an error argument first!_ This is inline with the false, it does not accept an error argument first!_ This is inline with the
way node libraries work with truth tests like path.exists. This operation is way node libraries work with truth tests like path.exists. This operation is
performed in parallel, so the results array may be in a different order to the performed in parallel, but the results array will be in the same order as the
original. original.


__Arguments__ __Arguments__
Expand All @@ -154,8 +152,7 @@ __Example__


The same as filter only the iterator is applied to each item in the array in The same as filter only the iterator is applied to each item in the array in
series. The next iterator is only called once the current one has completed series. The next iterator is only called once the current one has completed
processing, meaning the results array will be in the same order as the processing. The results array will be in the same order as the original.
original.




### reduce(arr, memo, iterator, callback) ### reduce(arr, memo, iterator, callback)
Expand Down Expand Up @@ -370,10 +367,10 @@ __Example__
write_file: ['get_data', 'make_folder', function(callback){ write_file: ['get_data', 'make_folder', function(callback){
// once there is some data and the directory exists, // once there is some data and the directory exists,
// write the data to a file in the directory // write the data to a file in the directory
}, }],
email_link: ['write_file', function(callback){ email_link: ['write_file', function(callback){
// once the file is written let's email a link to it... // once the file is written let's email a link to it...
} }]
}); });


This is a fairly trivial example, but to do this using the basic parallel and This is a fairly trivial example, but to do this using the basic parallel and
Expand Down
18 changes: 14 additions & 4 deletions lib/async.js
Expand Up @@ -52,9 +52,12 @@ var doSeries = function(fn){


var _map = function(eachfn, arr, iterator, callback){ var _map = function(eachfn, arr, iterator, callback){
var results = []; var results = [];
for(var i=0; i<arr.length; i++){
arr[i] = {index: i, value: arr[i]};
}
eachfn(arr, function(x, callback){ eachfn(arr, function(x, callback){
iterator(x, function(err, v){ iterator(x.value, function(err, v){
results.push(v); results[x.index] = v;
callback(err); callback(err);
}); });
}, function(err){ }, function(err){
Expand All @@ -81,13 +84,20 @@ exports.reduce = function(arr, memo, iterator, callback){


var _filter = function(eachfn, arr, iterator, callback){ var _filter = function(eachfn, arr, iterator, callback){
var results = []; var results = [];
for(var i=0; i<arr.length; i++){
arr[i] = {index: i, value: arr[i]};
}
eachfn(arr, function(x, callback){ eachfn(arr, function(x, callback){
iterator(x, function(v){ iterator(x.value, function(v){
if(v) results.push(x); if(v) results.push(x);
callback(); callback();
}); });
}, function(err){ }, function(err){
callback(results); callback(results.sort(function(a,b){
return a.index - b.index;
}).map(function(x){
return x.value;
}));
}); });
}; };
exports.filter = doParallel(_filter); exports.filter = doParallel(_filter);
Expand Down
46 changes: 37 additions & 9 deletions test/test-async.js
Expand Up @@ -163,20 +163,31 @@ exports['waterfall multiple callback calls'] = function(test){




exports['parallel'] = function(test){ exports['parallel'] = function(test){
var call_order = [];
async.parallel([ async.parallel([
function(callback){ function(callback){
setTimeout(function(){callback(null, 1);}, 25); setTimeout(function(){
call_order.push(1);
callback(null, 1);
}, 25);
}, },
function(callback){ function(callback){
setTimeout(function(){callback(null, 2);}, 50); setTimeout(function(){
call_order.push(2);
callback(null, 2);
}, 50);
}, },
function(callback){ function(callback){
setTimeout(function(){callback(null, 3,3);}, 15); setTimeout(function(){
call_order.push(3);
callback(null, 3,3);
}, 15);
} }
], ],
function(err, results){ function(err, results){
test.equals(err, null); test.equals(err, null);
test.same(results, [[3,3],1,2]); test.same(call_order, [3,1,2]);
test.same(results, [1,2,[3,3]]);
test.done(); test.done();
}); });
}; };
Expand Down Expand Up @@ -204,20 +215,31 @@ exports['parallel no callback'] = function(test){
}; };


exports['series'] = function(test){ exports['series'] = function(test){
var call_order = [];
async.series([ async.series([
function(callback){ function(callback){
setTimeout(function(){callback(null, 1);}, 25); setTimeout(function(){
call_order.push(1);
callback(null, 1);
}, 25);
}, },
function(callback){ function(callback){
setTimeout(function(){callback(null, 2);}, 50); setTimeout(function(){
call_order.push(2);
callback(null, 2);
}, 50);
}, },
function(callback){ function(callback){
setTimeout(function(){callback(null, 3,3);}, 15); setTimeout(function(){
call_order.push(3);
callback(null, 3,3);
}, 15);
} }
], ],
function(err, results){ function(err, results){
test.equals(err, null); test.equals(err, null);
test.same(results, [1,2,[3,3]]); test.same(results, [1,2,[3,3]]);
test.same(call_order, [1,2,3]);
test.done(); test.done();
}); });
}; };
Expand Down Expand Up @@ -345,12 +367,15 @@ exports['forEachSeries error'] = function(test){
}; };


exports['map'] = function(test){ exports['map'] = function(test){
var call_order = [];
async.map([1,3,2], function(x, callback){ async.map([1,3,2], function(x, callback){
setTimeout(function(){ setTimeout(function(){
call_order.push(x);
callback(null, x*2); callback(null, x*2);
}, x*25); }, x*25);
}, function(err, results){ }, function(err, results){
test.same(results, [2,4,6]); test.same(call_order, [1,2,3]);
test.same(results, [2,6,4]);
test.done(); test.done();
}); });
}; };
Expand All @@ -366,11 +391,14 @@ exports['map error'] = function(test){
}; };


exports['mapSeries'] = function(test){ exports['mapSeries'] = function(test){
var call_order = [];
async.mapSeries([1,3,2], function(x, callback){ async.mapSeries([1,3,2], function(x, callback){
setTimeout(function(){ setTimeout(function(){
call_order.push(x);
callback(null, x*2); callback(null, x*2);
}, x*25); }, x*25);
}, function(err, results){ }, function(err, results){
test.same(call_order, [1,3,2]);
test.same(results, [2,6,4]); test.same(results, [2,6,4]);
test.done(); test.done();
}); });
Expand Down Expand Up @@ -418,7 +446,7 @@ exports['filter'] = function(test){
async.filter([3,1,2], function(x, callback){ async.filter([3,1,2], function(x, callback){
setTimeout(function(){callback(x % 2);}, x*25); setTimeout(function(){callback(x % 2);}, x*25);
}, function(results){ }, function(results){
test.same(results, [1,3]); test.same(results, [3,1]);
test.done(); test.done();
}); });
}; };
Expand Down

0 comments on commit a57d319

Please sign in to comment.