Skip to content

Commit

Permalink
refactoring and unit test improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Caolan McMahon committed May 27, 2010
1 parent 950183f commit cf648d7
Show file tree
Hide file tree
Showing 2 changed files with 229 additions and 226 deletions.
286 changes: 128 additions & 158 deletions lib/async.js
Original file line number Diff line number Diff line change
@@ -1,127 +1,6 @@
var events = require('events');


exports.auto = function(tasks, callback){
callback = callback || function(){};
var keys = Object.keys(tasks);
if(!keys.length) return callback(null);

var completed = [];
var emitter = new events.EventEmitter();
emitter.addListener('taskComplete', function(){
if(completed.length == keys.length){
callback(null);
}
});

keys.forEach(function(k){
var task = (tasks[k] instanceof Function)? [tasks[k]]: tasks[k];
var taskCallback = function(err){
if(err){
callback(err);
// stop subsequent errors hitting the callback multiple times
callback = function(){};
}
else {
completed.push(k);
emitter.emit('taskComplete');
}
};
var requires = task.slice(0, Math.abs(task.length-1)) || [];
var ready = function(){
return requires.reduce(function(a,x){
return (a && completed.indexOf(x) != -1);
}, true);
};
if(ready()) task[task.length-1](taskCallback);
else {
var listener = function(){
if(ready()){
emitter.removeListener('taskComplete', listener);
task[task.length-1](taskCallback);
}
};
emitter.addListener('taskComplete', listener);
}
});
};

exports.waterfall = function(tasks, callback){
callback = callback || function(){};
var wrapIterator = function(iterator){
return function(){
var args = Array.prototype.slice.call(arguments);
var next = iterator.next();
if(next) args.push(wrapIterator(next));
else args.push(callback);
process.nextTick(function(){iterator.apply(null, args)});
};
};
wrapIterator(exports.iterator(tasks))();
};

exports.parallel = function(tasks, callback){
callback = callback || function(){};
var results = [];
tasks.forEach(function(fn){
fn(function(err){
if(err){
callback(err);
callback = function(){};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
results.push((args.length > 1) ? args: args[0]);
if(results.length == tasks.length){
callback(null, results);
}
}
});
});
};

exports.series = function(tasks, callback){
callback = callback || function(){};
var results = [];
var saveArgs = function(fn){
return function(err){
if(err){
callback(err);
callback = function(){};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
results.push((args.length > 1) ? args: args[0]);
fn.apply(null, args);
}
}
};
var wrapIterator = function(iterator){
return saveArgs(function(){
var next = iterator.next();
if(next) iterator(wrapIterator(iterator.next()));
else iterator(saveArgs(function(){
callback(null, results.slice(1));
}));
});
};
wrapIterator(exports.iterator(tasks))();
};

exports.iterator = function(tasks){
var makeCallback = function(index){
var fn = function(){
tasks[index].apply(null, arguments);
return fn.next();
}
fn.next = function(){
return (index < tasks.length-1)? makeCallback(index+1): undefined;
}
return fn;
};
return makeCallback(0);
};

exports.forEach = function(arr, iterator, callback){
var completed = 0;
arr.forEach(function(x){
Expand Down Expand Up @@ -156,21 +35,24 @@ exports.forEachSeries = function(arr, iterator, callback){
iterate();
};

exports.map = function(arr, iterator, callback){
var results = [];
exports.forEach(arr, function(x, callback){
iterator(x, function(err, v){
results.push(v);
callback(err);
});
}, function(err){
callback(err, results);
});

var doParallel = function(fn){
return function(){
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [exports.forEach].concat(args));
}
};
var doSeries = function(fn){
return function(){
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [exports.forEachSeries].concat(args));
}
};

exports.mapSeries = function(arr, iterator, callback){

var _map = function(eachfn, arr, iterator, callback){
var results = [];
exports.forEachSeries(arr, function(x, callback){
eachfn(arr, function(x, callback){
iterator(x, function(err, v){
results.push(v);
callback(err);
Expand All @@ -179,20 +61,12 @@ exports.mapSeries = function(arr, iterator, callback){
callback(err, results);
});
};
exports.map = doParallel(_map);
exports.mapSeries = doSeries(_map);

exports.reduce = function(arr, memo, iterator, callback){
exports.forEach(arr, function(x, callback){
iterator(memo, x, function(err, v){
memo = v;
callback(err);
});
}, function(err){
callback(err, memo);
});
};

exports.reduceSeries = function(arr, memo, iterator, callback){
exports.forEachSeries(arr, function(x, callback){
var _reduce = function(eachfn, arr, memo, iterator, callback){
eachfn(arr, function(x, callback){
iterator(memo, x, function(err, v){
memo = v;
callback(err);
Expand All @@ -201,22 +75,13 @@ exports.reduceSeries = function(arr, memo, iterator, callback){
callback(err, memo);
});
};
exports.reduce = doParallel(_reduce);
exports.reduceSeries = doSeries(_reduce);

exports.filter = function(arr, iterator, callback){
var results = [];
exports.forEach(arr, function(x, callback){
iterator(x, function(v){
if(v) results.push(x);
callback();
});
}, function(err){
callback(results);
});
};

exports.filterSeries = function(arr, iterator, callback){
var _filter = function(eachfn, arr, iterator, callback){
var results = [];
exports.forEachSeries(arr, function(x, callback){
eachfn(arr, function(x, callback){
iterator(x, function(v){
if(v) results.push(x);
callback();
Expand All @@ -225,6 +90,9 @@ exports.filterSeries = function(arr, iterator, callback){
callback(results);
});
};
exports.filter = doParallel(_filter);
exports.filterSeries = doSeries(_filter);


exports.some = function(arr, iterator, main_callback){
exports.forEach(arr, function(x, callback){
Expand Down Expand Up @@ -253,3 +121,105 @@ exports.every = function(arr, iterator, main_callback){
main_callback(true);
});
};


exports.auto = function(tasks, callback){
callback = callback || function(){};
var keys = Object.keys(tasks);
if(!keys.length) return callback(null);

var completed = [];
var emitter = new events.EventEmitter();
emitter.addListener('taskComplete', function(){
if(completed.length == keys.length){
callback(null);
}
});

keys.forEach(function(k){
var task = (tasks[k] instanceof Function)? [tasks[k]]: tasks[k];
var taskCallback = function(err){
if(err){
callback(err);
// stop subsequent errors hitting the callback multiple times
callback = function(){};
}
else {
completed.push(k);
emitter.emit('taskComplete');
}
};
var requires = task.slice(0, Math.abs(task.length-1)) || [];
var ready = function(){
return requires.reduce(function(a,x){
return (a && completed.indexOf(x) != -1);
}, true);
};
if(ready()) task[task.length-1](taskCallback);
else {
var listener = function(){
if(ready()){
emitter.removeListener('taskComplete', listener);
task[task.length-1](taskCallback);
}
};
emitter.addListener('taskComplete', listener);
}
});
};

exports.waterfall = function(tasks, callback){
callback = callback || function(){};
var wrapIterator = function(iterator){
return function(err){
if(err){
callback(err);
callback = function(){};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if(next) args.push(wrapIterator(next));
else args.push(callback);
process.nextTick(function(){iterator.apply(null, args)});
}
};
};
wrapIterator(exports.iterator(tasks))();
};

exports.parallel = function(tasks, callback){
callback = callback || function(){};
exports.map(tasks, function(fn, callback){
fn(function(err){
var args = Array.prototype.slice.call(arguments,1);
if(args.length <= 1) args = args[0];
callback.call(null, err, args || null);
});
}, callback);
};

exports.series = function(tasks, callback){
callback = callback || function(){};
exports.mapSeries(tasks, function(fn, callback){
fn(function(err){
var args = Array.prototype.slice.call(arguments,1);
if(args.length <= 1) args = args[0];
callback.call(null, err, args || null);
});
}, callback);
};

exports.iterator = function(tasks){
var makeCallback = function(index){
var fn = function(){
tasks[index].apply(null, arguments);
return fn.next();
}
fn.next = function(){
return (index < tasks.length-1)? makeCallback(index+1): undefined;
}
return fn;
};
return makeCallback(0);
};
Loading

0 comments on commit cf648d7

Please sign in to comment.