亲自打造Deferred对象

经过对比之后,决心学习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);
        }
    });
};
原文地址:https://www.cnblogs.com/kingge/p/5427994.html