经过对比之后,决心学习jQuery,自己打造一个Deferred对象.var util = require('./util.js');function Callbacks() {
var list = [], fireIndex = -1, firing, momery,
self = {
add: function () {
if (list) {
if (firing) {
fireIndex = list.length - 1;
}
(function add(args) {
for (var i = 0; i < args.length; i++) {
var value = args[i];
var type = util.type(value);
if (type === 'function') {
list.push(value);
}
else if (type === 'array') {
add(value);
}
}
})(arguments);
if (!firing && momery) {
this.fire.apply(this, momery);
}
}
return this;
},
remove: function () {
for (var i = 0; i < arguments.length; i++) {
var value = arguments[i];
var index = list.indexOf(v)
if (index > -1) {
list.splice(index, 1);
}
if (index <= firingIndex) {
firingIndex--;
}
}
return this;
},
has: function (fn) {
return fn ?list.indexOf(fn) > -1 :list.length > 0;
},
empty: function () {
if (list) {
list = [];
}
return this;
},
fire: function () {
momery = util.slice.call(arguments);
if (!firing) {
fireing = true;
while (++fireIndex < list.length) {
list[fireIndex].apply(this, momery);
}
list = [];
fireIndex = -1;
}
firing = false;
}
}
return self;
}
function Deferred() {
var state = "pending", scalls = Callbacks(), fcalls = Callbacks(), promise = {
state: function () {
return state;
},
always: function () {
var args=util.slice.call(arguments);
this.done(args).fail(args);
return this;
},
then: function (success, fail) {
switch (state) {
case "resolved":
scalls.add(success);
break;
case "rejected":
fcalls.add(fail);
break;
default:
scalls.add(success);
fcalls.add(fail);
break; }
return this;
},
done: function (success) { this.then(success, null);
return this;
},
fail: function (fail) {
this.then(null, fail);
return this;
},
resolve: function () {
if (state === "pending") {
state = "resolved";
scalls.fire.apply(this, arguments);
}
return this;
},
reject: function () {
if (state === "pending") {
state = "rejected";
fcalls.fire.apply(this, arguments);
}
return this;
}
};
return promise;
}
module.exports = {
Deferred: function () {
return Deferred();
},
when: function () {
var deferred = Deferred(), args = util.slice.call(arguments), ramin = len = arguments.length, context;
function update(i) {
return function (value) {
context[i] = arguments.length > 1?util.slice.call(arguments):value;
if (!--ramin) {
deferred.resolve.apply(deferred, context);
}
}
}
if (len > 0) {
context = new Array(len);
for (var i = 0; i < len; i++) {
var def = args[i];
if (def && util.type(def.then) === 'function') {
def.then.call(def, update(i), deferred.reject);
}
else {
update(i)(def);
}
}
}
return deferred;
}
}
测试用例:
var Q = require('./Deferred.js');
var deferred = Q.Deferred();
setTimeout(function () {
deferred.reject(1).then(function (r) { console.log("r4:" + r); }, function (e) { console.log("e4:" + e); });
}, 5000);
deferred.then(function (r) { console.log("r:" + r); }, function (e) { console.log("e:" + e); });
setTimeout(function () {
deferred.reject(2).then(function (r) { console.log("r2:" + r); }, function (e) { console.log("e2:" + e); });
}, 10000);
deferred.then(function (r) { console.log("r3:" + r); }, function (e) { console.log("e3:" + e); });
function A(){
var d = Q.Deferred().done(function (r) { console.log('A'+r); });
setTimeout(function () {
d.resolve('阿');
}, 1000);
return d;
}
function B() {
var d = Q.Deferred().done(function (r) { console.log('B' +r); /*d.resolve('b');*/ });
return d;
}
function C() {
var d = Q.Deferred().done(function (r) { console.log('C' +r); /*d.resolve('c');*/ });
setTimeout(function () {
}, 1000);
return d;
} Q.when(1, A() , 3).done(function (a,b,c) {
console.log(a);
console.log(b);
console.log(c);
}).fail(function (err) { console.log('err' + err); });
实际应用包装:
var d=require('./lib/deferred');
var util=require('./lib/util');
var mysql = require('mysql');
var settings = require('./config');
exports.process = function (wrappers) {
var con = mysql.createConnection(settings.db);
console.time('process');
con.beginTransaction(function (err) {
if (err) { console.error(err); }
else{
(function (wrappers){
var callee=arguments.callee;
if(util.type(wrappers)=='array'){
function wrapped(wraper){
var deferred= d.Deferred();
con.query(wraper.sql, wraper.data,function(err,rows){
if(err){
deferred.reject(err);
}
else{
deferred.resolve(rows);
}
});
deferred.then(wraper.scall,wraper.fcall);
return deferred;
}
var deferreds=[];
wrappers.forEach(function(wraper,i){
deferreds.push(wrapped(wraper));
});
d.when.apply(null,deferreds).then(function(){
con.commit(function (err) {
if (err) {
console.error(err);
return con.rollback(function () {
con.end(function (err) { if(err){console.error(err);} });
});
}
console.info('process success!');
});
},function(err){
console.error(err);
con.rollback(function () {
con.end(function (err) { if (err) { console.error(err); } });
});
}).always(function () { console.timeEnd('process'); });
}else if(util.type(wrappers)=='object'){
callee([wrappers]);
}
})(wrappers);
}
});
};