Skip to content

Instantly share code, notes, and snippets.

@raisch
Created July 14, 2011 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raisch/1083134 to your computer and use it in GitHub Desktop.
Save raisch/1083134 to your computer and use it in GitHub Desktop.
TaskRunner - runs any number of functions asynchronously and in order
var util=require('util'),
events=require('events'),
EventEmitter=events.EventEmitter;
/*
* TaskRunner - runs any number of functions asynchronously and in order
*
* var runner = new TaskRunner( func(s) || { options } );
*
* runner.init({
* trace: true,
* onCompleteHandler: function(args) {
* console.log('on completion, args is "%s"', args);
* }
* });
*
* runner.add(function(args){
* console.log('task called with args:%s', args);
* this.next(args);
* });
*
* runner.start('arg1','arg2');
*
* Public Methods
*
* new TaskRunner() - ctor
* accepts either an options object
* or any combination of functions and options objects
*
* ex.
* var r=new Runner({ tasks:[func1,func2], trace:true, onCompleteHandler:handler})
* var r=new Runner(func1, func2, { trace:true });
* etc
*
* init(options)
* initializes a runner
*
* addTask(func)
* adds a task the the task queue
*
* start()
* starts the queue
* any args are passed to task functions as f(args)
*
* Public Task Methods
*
* next(args)
* last(args)
* error(err,args)
* trace(msg)
*/
// runs any number of functions in order, asynchronously
// @ctor {TaskRunner}
// @params {function} zero or more functions
var TaskRunner = function(){
var args = Array.prototype.slice.call(arguments);
this._isTracing = false; // if true, report activity to console
this._taskqueue=[]; // holds the tasks to run
this._onCompleteHandler=function(args){ // default onComplete handler
console.log('completed with args:'+args);
};
this._onErrorHandler=function(err,args){ // default onError handler
console.log('error occurred with args:'+args);
throw err;
};
this._onTraceHandler=function(msg){
var args=Array.prototype.slice.call(arguments);
console.log('## trace: %s', msg);
};
// check args
for(var i=0,len=args.length;i<len;i++) {
var type=typeof args[i] || 'unknown';
if('function' === type) {
this._taskqueue.push(args[i].bind(this));
}
else if('object' === type) {
this.init(args[i]);
}
else {
throw 'arg#'+i+' must be either a function or an options object';
}
}
this._addListeners();
return this;
};
util.inherits(TaskRunner,events.EventEmitter);
// adds default listeners
TaskRunner.prototype._addListeners=function(){
this.on('complete',function(args){
if(this._onCompleteHandler && 'function' === typeof this._onCompleteHandler) {
(this._onCompleteHandler)(args);
}
});
this.on('error', function(err,args){
if(this._onErrorHandler && 'function' === typeof this._onErrorHandler) {
(this._onErrorHandler)(err,args);
}
});
return this;
};
// add a new task to the queue
TaskRunner.prototype.addTask=function(task) {
if('function' !== typeof task) {
throw 'task must be a function';
}
this._taskqueue.push(task.bind(this));
};
// initializes a TaskRunner with optional tasks
// and onComplete and onError handlers
TaskRunner.prototype.init=function(options) {
this._isTracing = options.trace || false;
if(options.tasks && options.tasks instanceof Array) {
for(var i=0,len=options.tasks.length;i<len;i++) {
this.addTask(options.tasks[i]);
}
}
if(options.onCompleteHandler && 'function' === typeof options.onCompleteHandler) {
this._onCompleteHandler=options.onCompleteHandler;
}
if(options.onErrorHandler && 'function' === typeof options.onErrorHandler) {
this._onErrorHandler=options.onErrorHandler;
}
return this;
};
// runs the next task in the queue, to be called within a task
TaskRunner.prototype.next=function(args){
if(this._taskqueue.length > 0) {
try {
(this._taskqueue.shift())(args);
}
catch(err) {
this.emit('error', err, args);
}
}
else {
this.emit('complete',args);
}
};
// stops running tasks, to be called within a task
TaskRunner.prototype.last=function(args){
this.emit('complete',args);
};
// reports an error running a task, to be called with a task
TaskRunner.prototype.error=function(err /*, ... */){
if(this._onErrorHandler && 'function' === typeof this._onErrorHandler) {
(this._onErrorHandler).call(arguments);
}
else {
throw err;
}
};
// sends a msg to the onTraceHandler
TaskRunner.prototype.trace=function(msg) {
if(this._isTracing && this._onTraceHandler && 'function' === typeof this._onTraceHandler) {
(this._onTraceHandler)(msg);
}
};
// starts processing tasks
TaskRunner.prototype.start=function(/* ... */){
var args = Array.prototype.slice.call(arguments);
this.next(args);
};
// DEMO
// simple task to add the first two items on the args list and push the result back onto args
function adder(args){
var x=Number(args.shift()||0),
y=Number(args.shift()||0),
sum=Number(x+y);
this.trace('running adder with x:'+x+', y:'+y+', args:'+args);
args.push(sum);
this.next(args); // run the next task in the queue
}
// create and start a new TaskRunner
var runner=new TaskRunner(
{
trace: true,
onCompleteHandler: function(args){
console.log('the result of (1+2) + (3+4) is '+args.shift());
},
},
adder, // adds 1+2, pushes 3
adder, // adds 3+4, pushes 7
adder // adds 3+7, pushes 10
).start(1,2,3,4);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment