Created
July 14, 2011 18:51
-
-
Save raisch/1083134 to your computer and use it in GitHub Desktop.
TaskRunner - runs any number of functions asynchronously and in order
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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