Permalink
Browse files

ensure map and filter results stay in the same order when processing …

…in parallel
  • Loading branch information...
1 parent ea4c476 commit a57d319468960d4e56ff10cc032212976b7cb849 @caolan committed Jun 9, 2010
Showing with 58 additions and 23 deletions.
  1. +7 −10 README.md
  2. +14 −4 lib/async.js
  3. +37 −9 test/test-async.js
View
@@ -99,9 +99,8 @@ error to this callback, the main callback for the map 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. The
-results array can be in a different order to the source array. If you need the
-order to be the same, then use mapSeries instead.
+there is no guarantee that the iterator functions will complete in order, however
+the results array will be in the same order as the original array.
__Arguments__
@@ -123,8 +122,7 @@ __Example__
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
-processing, meaning the results array will be in the same order as the
-original.
+processing. The results array will be in the same order as the original.
### filter(arr, iterator, callback)
@@ -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
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
-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.
__Arguments__
@@ -154,8 +152,7 @@ __Example__
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
-processing, meaning the results array will be in the same order as the
-original.
+processing. The results array will be in the same order as the original.
### reduce(arr, memo, iterator, callback)
@@ -370,10 +367,10 @@ __Example__
write_file: ['get_data', 'make_folder', function(callback){
// once there is some data and the directory exists,
// write the data to a file in the directory
- },
+ }],
email_link: ['write_file', function(callback){
// 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
View
@@ -52,9 +52,12 @@ var doSeries = function(fn){
var _map = function(eachfn, arr, iterator, callback){
var results = [];
+ for(var i=0; i<arr.length; i++){
+ arr[i] = {index: i, value: arr[i]};
+ }
eachfn(arr, function(x, callback){
- iterator(x, function(err, v){
- results.push(v);
+ iterator(x.value, function(err, v){
+ results[x.index] = v;
callback(err);
});
}, function(err){
@@ -81,13 +84,20 @@ exports.reduce = function(arr, memo, iterator, callback){
var _filter = function(eachfn, arr, iterator, callback){
var results = [];
+ for(var i=0; i<arr.length; i++){
+ arr[i] = {index: i, value: arr[i]};
+ }
eachfn(arr, function(x, callback){
- iterator(x, function(v){
+ iterator(x.value, function(v){
if(v) results.push(x);
callback();
});
}, 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);
View
@@ -163,20 +163,31 @@ exports['waterfall multiple callback calls'] = function(test){
exports['parallel'] = function(test){
+ var call_order = [];
async.parallel([
function(callback){
- setTimeout(function(){callback(null, 1);}, 25);
+ setTimeout(function(){
+ call_order.push(1);
+ callback(null, 1);
+ }, 25);
},
function(callback){
- setTimeout(function(){callback(null, 2);}, 50);
+ setTimeout(function(){
+ call_order.push(2);
+ callback(null, 2);
+ }, 50);
},
function(callback){
- setTimeout(function(){callback(null, 3,3);}, 15);
+ setTimeout(function(){
+ call_order.push(3);
+ callback(null, 3,3);
+ }, 15);
}
],
function(err, results){
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();
});
};
@@ -204,20 +215,31 @@ exports['parallel no callback'] = function(test){
};
exports['series'] = function(test){
+ var call_order = [];
async.series([
function(callback){
- setTimeout(function(){callback(null, 1);}, 25);
+ setTimeout(function(){
+ call_order.push(1);
+ callback(null, 1);
+ }, 25);
},
function(callback){
- setTimeout(function(){callback(null, 2);}, 50);
+ setTimeout(function(){
+ call_order.push(2);
+ callback(null, 2);
+ }, 50);
},
function(callback){
- setTimeout(function(){callback(null, 3,3);}, 15);
+ setTimeout(function(){
+ call_order.push(3);
+ callback(null, 3,3);
+ }, 15);
}
],
function(err, results){
test.equals(err, null);
test.same(results, [1,2,[3,3]]);
+ test.same(call_order, [1,2,3]);
test.done();
});
};
@@ -345,12 +367,15 @@ exports['forEachSeries error'] = function(test){
};
exports['map'] = function(test){
+ var call_order = [];
async.map([1,3,2], function(x, callback){
setTimeout(function(){
+ call_order.push(x);
callback(null, x*2);
}, x*25);
}, function(err, results){
- test.same(results, [2,4,6]);
+ test.same(call_order, [1,2,3]);
+ test.same(results, [2,6,4]);
test.done();
});
};
@@ -366,11 +391,14 @@ exports['map error'] = function(test){
};
exports['mapSeries'] = function(test){
+ var call_order = [];
async.mapSeries([1,3,2], function(x, callback){
setTimeout(function(){
+ call_order.push(x);
callback(null, x*2);
}, x*25);
}, function(err, results){
+ test.same(call_order, [1,3,2]);
test.same(results, [2,6,4]);
test.done();
});
@@ -418,7 +446,7 @@ exports['filter'] = function(test){
async.filter([3,1,2], function(x, callback){
setTimeout(function(){callback(x % 2);}, x*25);
}, function(results){
- test.same(results, [1,3]);
+ test.same(results, [3,1]);
test.done();
});
};

0 comments on commit a57d319

Please sign in to comment.