Created
October 3, 2012 23:28
-
-
Save MStumpp/3830548 to your computer and use it in GitHub Desktop.
chain.js - add function chaining capability
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
function chainify(clazz) { | |
var Chain = function() {}; | |
Chain.prototype.exec = function() { | |
return this.c_process(); | |
}; | |
Chain.prototype.c_chain = function(func, args) { | |
if (!func) | |
throw new Error('Provide a function to be chained.'); | |
var manager; | |
if (!this.hasOwnProperty('manager')) { | |
manager = { | |
base : this, | |
timerId : null, | |
executing : false, | |
queue : [] | |
}; | |
} else { | |
manager = this.manager; | |
} | |
var f = function() {}; | |
f.prototype = manager.base.constructor.prototype; | |
f.prototype.constructor = f; | |
var obj = function(func, args, cb, manager) { | |
this.func = func; | |
this.args = args; | |
this.cb = cb; | |
this.manager = manager; | |
}; | |
obj.prototype = new f(); | |
obj.prototype.constructor = obj; | |
var argsTmp = null; | |
var cb = null; | |
if (args) { | |
argsTmp = args; | |
// check if last arg is a function | |
// if so, register it as callback | |
if (args.length > 0) { | |
if (typeof args[args.length-1] === 'function') { | |
cb = args[args.length-1]; | |
} | |
} | |
} | |
var objIns = new obj(func, argsTmp, cb, manager); | |
objIns.manager.queue.push(objIns); | |
objIns.manager.timerId = setTimeout(function() { objIns.c_process(); }, 1); | |
return objIns; | |
}; | |
Chain.prototype.c_process = function() { | |
var self = this; | |
if (!this.manager) | |
return this; | |
if (this.manager.timerId) | |
clearTimeout(this.manager.timerId); | |
if (this.manager.queue.length > 0) { | |
var elem = this.manager.queue.shift(); | |
var context = this; | |
context.c_next = function() { | |
if (elem.cb) { | |
var context = this; | |
context.c_next = function() { | |
self.c_process.apply(self); | |
}; | |
elem.cb.apply(context); | |
} else { | |
self.c_process.apply(self); | |
} | |
}; | |
elem.func.apply(context, elem.args); | |
} | |
return this; | |
}; | |
Chain.prototype.c_clear = function() { | |
if (!this.manager) | |
return this; | |
if (this.manager.timerId) | |
clearTimeout(this.manager.timerId); | |
if (this.manager.queue) | |
this.manager.queue.length = 0; | |
return this; | |
}; | |
Chain.prototype.c_delay = function() { | |
if (!this.manager) | |
return this; | |
if (this.manager.timerId) | |
clearTimeout(this.manager.timerId); | |
return this; | |
}; | |
Chain.prototype.c_getSuccessors = function() { | |
if (!this.manager) | |
return []; | |
if (this.manager.queue) | |
return this.manager.queue; | |
return []; | |
}; | |
Chain.prototype.c_getPredecessors = function() { | |
if (!this.manager) | |
return []; | |
if (this.manager.queue) | |
return this.manager.queue; | |
return []; | |
}; | |
for (var prop in Chain.prototype) | |
clazz.prototype[prop] = Chain.prototype[prop]; | |
return clazz; | |
} | |
var Model = function() {}; | |
Model.prototype.func1 = function() { | |
//this.c_clear(); synchronous, may be called this way | |
//this.c_delay(); synchronous, may be called this way | |
//this.c_getPredecessors(), synchronous, returns all previous chained functions | |
console.log('func1 has ' + this.c_getPredecessors().length + ' preceding functions'); | |
return this.c_delay().c_chain(function() { | |
// this.c_getSuccessors(), synchron, returns all succeding chained functions | |
console.log('func1 has ' + this.c_getSuccessors().length + ' succeding functions'); | |
//Obj.func2().func3(); | |
console.log('func1 processing...'); | |
var self = this; | |
setTimeout(function() { | |
self.c_next(); | |
}, 3000); | |
//this.c_next(); | |
}, arguments); | |
}; | |
Model.prototype.func2 = function() { | |
console.log('func2 has ' + this.c_getPredecessors().length + ' preceding functions'); | |
return this.c_delay().c_chain(function() { | |
console.log('func2 has ' + this.c_getSuccessors().length + ' succeding functions'); | |
console.log('func2 processing...'); | |
this.c_next(); | |
}); | |
}; | |
Model.prototype.func3 = function() { | |
console.log('func3 has ' + this.c_getPredecessors().length + ' preceding functions'); | |
return this.c_delay().c_chain(function() { | |
console.log('func3 has ' + this.c_getSuccessors().length + ' succeding functions'); | |
console.log('func3 processing...'); | |
this.c_next(); | |
}); | |
}; | |
Model.prototype.func4 = function() { | |
console.log('func4 has ' + this.c_getPredecessors().length + ' preceding functions'); | |
return this.c_delay().c_chain(function() { | |
console.log('func4 has ' + this.c_getSuccessors().length + ' succeding functions'); | |
console.log('func4 processing...'); | |
this.c_next(); | |
}); | |
}; | |
chainify(Model); | |
var Obj = new Model(); | |
Obj.func1(function() { | |
console.log('func1 processed!'); | |
this.c_next(); | |
}).func4().func3().func3(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment