Skip to content

Instantly share code, notes, and snippets.

@MStumpp
Created October 3, 2012 23:28
Show Gist options
  • Save MStumpp/3830548 to your computer and use it in GitHub Desktop.
Save MStumpp/3830548 to your computer and use it in GitHub Desktop.
chain.js - add function chaining capability
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