butler.js | |
---|---|
A couple of dependencies | var util = require("util"),
events = require("events"); |
The Butler! Initializes actions and defines himself as not working | function Butler() {
events.EventEmitter.call(this);
this.actions = [];
this._working = false;
this._last_wait = 0;
} |
Butler inherits from | util.inherits(Butler, events.EventEmitter); |
Add an asynchronous call to the Butler. The first parameter is a call reference and the other parameters are possible arguments (if needed). A callback will be appended to the arguments so your asynchronous call must have a last parameter which is the return callback that must have an error argument as first parameter or don't have any arguments at all. | Butler.prototype.add = function () {
var params = Array.prototype.slice.apply(arguments);
if (!params.length || typeof params[0] != "function") {
throw new Error({ code: 1, message: "Function not specified" });
}
this.actions.push({
"call": params[0],
"args": params.slice(1)
});
return this;
}; |
Add a waiting callback. This immediately start running the previously added callbacks one by one. After all run successfull, this callback is executed with 3 parameters: an error object (if some callback in the middle fails), the return parameters from the final callback and a butler object with 2 methods:
| Butler.prototype.wait = function (cb) {
this.actions.push({
"wait": cb
});
this.resume();
return this;
}; |
Instructs the butler that the previous calls are to be runned in parallel, without arguments passing from one to another. The callback is executed at the end of all the asynchronous calls with the result of all the callbacks. | Butler.prototype.parallel = function (cb) {
this.actions.push({
"parallel": cb
});
this.resume();
return this;
};
Butler.prototype.resume = function (params) {
if (this._working || !this.actions.length) {
return;
}
this._working = true;
var parallelResume = -1;
for (var i = 0; i < this.actions.length; i++) {
if (this.actions[i].hasOwnProperty("call")) continue;
if (this.actions[i].hasOwnProperty("wait")) break;
if (this.actions[i].hasOwnProperty("parallel")) {
parallelResume = i;
break;
}
}
if (parallelResume == 0) { |
??? | return console.log("parallel resume without anything to run in parallel");
} else if (parallelResume > 0) {
var actions = this.actions.splice(0, parallelResume + 1),
parallelCb = actions.pop(),
missingActions = actions.length,
actionReturns = [];
this._last_wait = 0;
for (var i = 0; i < actions.length; i++) {
actions[i].args.push(
(function (butler, n) {
return function () {
console.log("action %d finished", n);
missingActions--;
actionReturns[n] = Array.prototype.slice.apply(arguments);
if (missingActions == 0) {
console.log("parallel done!");
butler._working = false;
parallelCb.parallel(actionReturns); |
butler.resume(); | }
};
})(this, i)
);
actions[i].call.apply(actions[i].call, actions[i].args);
}
return;
}
var action = this.actions.splice(0, 1).pop();
params = params || this._next_params;
delete this._next_params;
if (action.hasOwnProperty("call")) {
if (params && params.length) {
for (var i = params.length - 1; i >= 0; i--) {
action.args.unshift(params[i]);
}
}
action.args.push(
(function (butler) {
return function () {
butler._working = false;
butler._handleReturn(Array.prototype.slice.apply(arguments));
};
})(this)
);
this._last_wait++;
action.call.apply(action.call, action.args);
return;
}
if (action.hasOwnProperty("wait")) {
var butler = (function (butler) {
return {
"set": function () {
butler._next_params = Array.prototype.slice.apply(arguments);
return this;
},
"resume": function () {
butler.resume();
}
};
})(this);
this._next_params = params || [];
this._last_wait = 0;
this._working = false;
var ret = action.wait.apply(action.wait, [ null, this._next_params, butler ]);
if (ret !== false) {
this.resume(typeof ret == "object" ? ret : this._next_params);
}
return;
}
};
Butler.prototype._handleReturn = function (params) {
if (!params.length) {
return this.resume();
}
if (params[0]) { |
error | for (var i = 0; i < this.actions.length; i++) {
if (this.actions[i].hasOwnProperty("wait")) {
var action = this.actions.splice(0, i + 1).pop(),
butler = (function (butler) {
return {
"set": function () {
butler._next_params = Array.prototype.slice.apply(arguments);
return this;
},
"resume": function () {
butler.resume();
}
};
})(this);
params[0].callbackIndex = this._last_wait;
this._last_wait = 0;
this._working = false;
var ret = action.wait.apply(action.wait, [ params[0], null, butler ]);
if (ret !== false) {
this.resume(typeof ret == "object" ? ret : null);
}
return;
}
}
return console.log("error without a wait() call to handle!", params[0], this._last_wait);
}
this.resume(params.slice(1));
};
exports.Butler = Butler;
|