• JS搞基指南----延迟对象入门提高资料整理


      JavaScript的Deferred是比较高大上的东西,  主要的应用还是主ajax的应用,  因为JS和nodeJS这几年的普及,  前端的代码越来越多,  各种回调套回调再套回调实在太让人崩溃, 所以就从后端拖了一个延迟对象这货, 用来解决回调地狱这个问题 。

       我们使用ajax的时候多数都是为ajax添加回调 ,然后异步向服务器发送请求, 比如如下原生的XHR代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>
            填坑必备
            </title>
        </head>
        <body>
            <div id="results">
                data
            </div>
            <script>
                var results = document.getElementById('results');
                var r = new XMLHttpRequest();
                r.open("GET", "http://www.filltext.com?rows=10&f={firstName}", true);
                r.onreadystatechange = function () {
                    if (r.readyState != 4 || r.status != 200) return;
                    var data = JSON.parse(r.responseText);
                    for (i=0;i<data.length;i++){
                        results.innerHTML += '<li>'+data[i].f+'</li>'
                    };
                };
                r.send();
            </script>
        </body>
    </html>

       因为jQ1.5以后版本的ajax的实例对象继承了延迟对象, 我们可以使用ajax实例的then或者done以及fail等等方法 ,所以上面的代码可以改写为:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>
            填坑必备
            </title>
        </head>
      //bootcdn这个cdn满好用的, 上面好多库哇, 推荐一下; <script src="http://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script> <body> <div id="results"> data </div> <script>
                                          //then : $.get, $.post, $.ajax返回的对象是延迟对象(deferred);
    $.get("http://www.filltext.com?rows=10&f={firstName}").then(function(data){
              console.log(data);
    for (i=0;i<data.length;i++){ $("#results").html(function(){ return $.map(data,function( obj ) { return obj.f }).join(" || ") }) }; }); </script> </body> </html>

      下划线的这个是网上抄的,不想看可以略过:异步模式在web编程中变得越来越重要,对于web主流语言Javscript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promise的抽象(有时也称之为deferred)。通过这些库,开发人员能够在实际编程中使用 promise模式。

      先说下延迟对象的三种状态, 当一个延迟对象被初始化那么该对象默认为peding状态

        1:pending等待状态

         2:fulfilled执行完成状态

         3:rejected拒绝状态;

      延迟对象的两个主要方法:

        1:add 这个方法是添加成功回调

        2:fail 这个方法是添加拒绝回调

      延迟对象比较高级的方法:

        1:then方法; 该方法返回一个包裹了旧延迟对象新延迟对象

        2:promise方法;这个对象返回的是阉割后的Defered(延迟对象),主要作用是保护原来延迟对象;

        3:when这个方法不是在延迟对象的实例上, (根据库的不同, when这个方法在不同的地方,比如jQ的when方法是$.when,别的库( •̀ ω •́ ) 也说不准, 反正when的源代码是在Deferred附近), 但是和延迟对象息息相关, 因为这个方法返回的也是一个延迟对象, 顾名思义when的作用就是:when你传的几个延迟对象全部resolve以后, when的返回实例会resolve....懂得自然懂, 不急;

       下面这张图是jQ这个Deferred实例对象方法, 提供参考:

      以下的JS代码是《司徒框架设计》里面介绍的延迟对象mochikit, 可以自己在控制台跟踪一下就知道执行的流程:
    mochikit延迟对象源代码如下, 这个延迟对象很好理解;GitHub的地址是: https://github.com/mochi/mochikit/

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>无标题文档</title>
    </head>
    <body>
    <script>
    /** @id MochiKit.Async.Deferred */
    var MochiKitDeferred = function (/* optional */ canceller) {
        this.chain = [];
        this.id = this._nextId();
        this.fired = -1;
        this.paused = 0;
        this.results = [null, null];
        this.canceller = canceller;
        this.silentlyCancelled = false;
        this.chained = false;
        this.finalized = false;
        this.GenericError = function(msg){
            return new Error("GenericError"+msg);
        };
        this.CancelledError = function(msg) {
            return new Error("CancelledError"+msg);
        };
    };
    
    MochiKitDeferred.prototype = {
        /** @id MochiKit.Async.Deferred.prototype.repr */
        repr: function () {
            return 'Deferred(' + this.id + ', ' + this.state() + ')';
        },
    
        toString: "",
    
        _nextId: function() {
            //return setTimeout("",0),中间要有一个空格, 要么不行;
            return setTimeout(" ",0);
        },
    
        /** @id MochiKit.Async.Deferred.prototype.state */
        state: function () {
            if (this.fired == -1) {
                return 'unfired';
            } else if (this.fired === 0) {
                return 'success';
            } else {
                return 'error';
            }
        },
        /** @id MochiKit.Async.Deferred.prototype.cancel */
        cancel: function (e) {
            var self = this;
            if (this.fired == -1) {
                if (this.canceller) {
                    this.canceller(this);
                } else {
                    this.silentlyCancelled = true;
                }
                if (this.fired == -1) {
                    if (typeof(e) === 'string') {
                        e = new self.GenericError(e);
                    } else if (!(e instanceof Error)) {
                        e = new self.CancelledError(this);
                    }
                    this.errback(e);
                }
            } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
                this.results[0].cancel(e);
            }
        },
    
        _resback: function (res) {
            /***
    
             The primitive that means either callback or errback
    
             ***/
            this.fired = ((res instanceof Error) ? 1 : 0);
            this.results[this.fired] = res;
            if (this.paused === 0) {
                this._fire();
            }
        },
    
        _check: function () {
            if (this.fired != -1) {
                if (!this.silentlyCancelled) {
                    throw new MochiKit.Async.AlreadyCalledError(this);
                }
                this.silentlyCancelled = false;
                return;
            }
        },
    
        /** @id MochiKit.Async.Deferred.prototype.callback */
        callback: function (res) {
            this._check();
            if (res instanceof MochiKit.Async.Deferred) {
                throw new Error("Deferred instances can only be chained if they are the result of a callback");
            }
            this._resback(res);
        },
    
        /** @id MochiKit.Async.Deferred.prototype.errback */
        errback: function (res) {
            this._check();
            var self = MochiKit.Async;
            if (res instanceof self.Deferred) {
                throw new Error("Deferred instances can only be chained if they are the result of a callback");
            }
            if (!(res instanceof Error)) {
                res = new self.GenericError(res);
            }
            this._resback(res);
        },
    
        /** @id MochiKit.Async.Deferred.prototype.addBoth */
        addBoth: function (fn) {
            return this.addCallbacks(fn, fn);
        },
    
        /** @id MochiKit.Async.Deferred.prototype.addCallback */
        addCallback: function (fn) {
            if (arguments.length > 1) {
                fn = MochiKit.Base.partial.apply(null, arguments);
            }
            return this.addCallbacks(fn, null);
        },
    
        /** @id MochiKit.Async.Deferred.prototype.addErrback */
        addErrback: function (fn) {
            if (arguments.length > 1) {
                fn = MochiKit.Base.partial.apply(null, arguments);
            }
            return this.addCallbacks(null, fn);
        },
    
        /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
        addCallbacks: function (cb, eb) {
            if (this.chained) {
                throw new Error("Chained Deferreds can not be re-used");
            }
            if (this.finalized) {
                throw new Error("Finalized Deferreds can not be re-used");
            }
            this.chain.push([cb, eb]);
    
            //已经触发了, 让他emitDirect;
            if (this.fired >= 0) {
                this._fire();
            }
            return this;
        },
    
        _fire: function () {
            /***
    
             Used internally to exhaust the callback sequence when a result
             is available.
    
             ***/
            var chain = this.chain;
            var fired = this.fired;
            var res = this.results[fired];
            var self = this;
            var cb = null;
            while (chain.length > 0 && this.paused === 0) {
                // Array
                var pair = chain.shift();
                var f = pair[fired];
                if (f === null) {
                    continue;
                };
                try {
                    res = f(res);
                    fired = ((res instanceof Error) ? 1 : 0);
                    if (res instanceof MochiKitDeferred) {
                        //new如果返回的是延迟对象, 那么this的.paused就被卡住了;
                        cb = function (res) {
                            self.paused--;
                            self._resback(res);
                        };
                        /*
                        */
                        this.paused++;
                    };
                } catch (err) {
                    fired = 1;
                    if (!(err instanceof Error)) {
                        err = new MochiKitDeferred.GenericError(err);
                    }
                    res = err;
                };
            };
            this.fired = fired;
            this.results[fired] = res;
            if (this.chain.length == 0 && this.paused === 0 && this._finalizer) {
                this.finalized = true;
                this._finalizer(res);
            }
            if (cb && this.paused) {
                // this is for "tail recursion" in case the dependent deferred
                // is already fired
                res.addBoth(cb);
                res.chained = true;
            }
        }
    };
    
    //这个延迟对象最常用方式是这样:
    var df = new MochiKitDeferred();
    df.addBoth(function(){ 
        console.log(1);
    }).addBoth(function(){ 
        console.log(2) 
    })
    df._resback(); // 控制他打出 ==>1 
    
       2 
    
    ;

    //这个延迟对象最常用方式是这样; //当然, 你可以把上面一个函数的返回值作为下一个函数的参数, 如下: var df = new MochiKitDeferred(); df.addBoth(function(){ return 0 }).addBoth(function(arg){ console.log(arg); return 1; }).addBoth(function(arg){ console.log(arg); return 2; }).addBoth(function(arg){ console.log(arg); }) df._resback(); // 控制他打出 ==>1 2 ; </script> </body> </html>


      博客园上博友教你写一个比较简单的延迟对象, 地址是: http://www.cnblogs.com/ygm125/p/3735677.html

      是代码量比较少的, 也好理解, 实在不懂就开控制器一步一步跟踪, 多看几遍, 不懂都说不过去:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>无标题文档</title>
    </head>
    <body>
    <script>
    
    (function(window,undefined){
    
        var PENDING = undefined, FULFILLED = 1, REJECTED = 2;
        
        var isFunction = function(obj){
            return 'function' === typeof obj;
        }
        var isArray = function(obj) {
            return Object.prototype.toString.call(obj) === "[object Array]";
        }
        var isThenable = function(obj){
            return obj && typeof obj['then'] == 'function';
        }
        
        var transition = function(status,value){
            var promise = this;
            if(promise._status !== PENDING) return;
            // 所以的执行都是异步调用,保证then是先执行的
            setTimeout(function(){
                promise._status = status;
                publish.call(promise,value);
            });
        }
        var publish = function(val){
            var promise = this,
                fn,
                st = promise._status === FULFILLED,
                queue = promise[st ? '_resolves' : '_rejects'];
            
            while(fn = queue.shift()) {
                val = fn.call(promise, val) || val;
            }
            promise[st ? '_value' : '_reason'] = val;
            promise['_resolves'] = promise['_rejects'] = undefined;
        }
        
        var Promise = function(resolver){
            if (!isFunction(resolver))
                throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
            if(!(this instanceof Promise)) return new Promise(resolver);
        
            var promise = this;
            promise._value;
            promise._reason;
            promise._status = PENDING;
            promise._resolves = [];
            promise._rejects = [];
            
            var resolve = function(value){
                transition.apply(promise,[FULFILLED].concat([value]));
            }
            var reject = function(reason){
                transition.apply(promise,[REJECTED].concat([reason]));
            }
            
            resolver(resolve,reject);
        }
        
        Promise.prototype.then = function(onFulfilled,onRejected){
            var promise = this;
            // 每次返回一个promise,保证是可thenable的
            return Promise(function(resolve,reject){
                function callback(value){
                  var ret = isFunction(onFulfilled) && onFulfilled(value) || value;
                  if(isThenable(ret)){
                    ret.then(function(value){
                       resolve(value);
                    },function(reason){
                       reject(reason);
                    });
                  }else{
                    resolve(ret);
                  }
                }
                function errback(reason){
                    reason = isFunction(onRejected) && onRejected(reason) || reason;
                    reject(reason);
                }
                if(promise._status === PENDING){
                    promise._resolves.push(callback);
                    promise._rejects.push(errback);
                }else if(promise._status === FULFILLED){ // 状态改变后的then操作,立刻执行
                    callback(promise._value);
                }else if(promise._status === REJECTED){
                    errback(promise._reason);
                }
            });
        }
        
        Promise.prototype.catch = function(onRejected){
            return this.then(undefined, onRejected)
        }
        
        Promise.prototype.delay = function(ms){
            return this.then(function(val){
                return Promise.delay(ms,val);
            })
        }
        
        Promise.delay = function(ms,val){
            return Promise(function(resolve,reject){
                setTimeout(function(){
                    resolve(val);
                },ms);
            })
        }
        
        Promise.resolve = function(arg){
            return Promise(function(resolve,reject){
                resolve(arg)
            })
        }
        
        Promise.reject = function(arg){
            return Promise(function(resolve,reject){
                reject(arg)
            })
        }
        
        Promise.all = function(promises){
            if (!isArray(promises)) {
                throw new TypeError('You must pass an array to all.');
            }
            return Promise(function(resolve,reject){
                var i = 0,
                    result = [],
                    len = promises.length;
        
                function resolver(index) {
                  return function(value) {
                    resolveAll(index, value);
                  };
                }
        
                function rejecter(reason){
                    reject(reason);
                }
        
                function resolveAll(index,value){
                    result[index] = value;
                    if(index == len - 1){
                        resolve(result);
                    }
                }
        
                for (; i < len; i++) {
                    promises[i].then(resolver(i),rejecter);
                }
            });
        }
        
        Promise.race = function(promises){
            if (!isArray(promises)) {
                throw new TypeError('You must pass an array to race.');
            }
            return Promise(function(resolve,reject){
                var i = 0,
                    len = promises.length;
        
                function resolver(value) {
                    resolve(value);
                }
        
                function rejecter(reason){
                    reject(reason);
                }
        
                for (; i < len; i++) {
                    promises[i].then(resolver,rejecter);
                }
            });
        }
        
        window.Promise = Promise;
    
    })(window);
    
    //常见的使用方式如下:
    var getData100 = function(){
        return Promise(function(resolve,reject){
            setTimeout(function(){
                resolve('100ms');
            },100);
        });
    }
    
    var getData200 = function(){
        return Promise(function(resolve,reject){
            setTimeout(function(){
                resolve('200ms');
            },200);
        });
    }
    
    getData100().then(function(data){
        console.log(data); // 100ms
        return getData200();
    }).then(function(data){
        console.log(data); // 200ms
        return data + data;
    }).then(function(data){
        console.log(data) // 200ms200ms
    });
    </script>
    </body>
    </html>
    View Code

      

      公司这边的老段写的Deferred, 是从TypeScript编译成js的, 因为这个东西比较简单, 应该不算泄露公司机密哇, 代码的最后有几个使用的实例, 你点击运行即可查看, 有兴趣自己写一个延迟对象, 印象会更加深刻:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>无标题文档</title>
    </head>
    <body>
    <script>
    
    //d为目标对象, b为一个函数对象;
    var __extends = this.__extends || function (d, b) {
        //继承了静态属性
        for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        function __() { this.constructor = d; }
        //继承了原型
        __.prototype = b.prototype;
        d.prototype = new __();
    };
    
    //Promise这个构造器, Deferred继承Promise;
    var Promise = (function () {
        function Promise() {
        }
        /**
         * onDone/onFail 应该返回值(或抛出异常),即不应返回 undefined,忘记返回值通常是 Bug,因此会在控制台给出警告。
         * 如果确实不需要返回值,可返回 null。
         */
        Promise.prototype.then = function (onDone, onFail) {
            return null;
        };
        Object.defineProperty(Promise.prototype, "status", {
            get: function () {
                return 0;
            },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Promise.prototype, "result", {
            get: function () {
                return undefined;
            },
            enumerable: true,
            configurable: true
        });
        Promise.prototype.done = function (onDone) {
            return this;
        };
        Promise.prototype.fail = function (onFail) {
            return this;
        };
        Promise.prototype.progress = function (onProgress) {
            return this;
        };
    
        Promise.when = function (promises) {
            var allDone = new Deferred();
            if (!promises.length) {
                allDone.resolve([]);
                return allDone;
            }
            var resolved = 0;
            for (var i = 0; i < promises.length; i++) {
                promises[i].done(function (v) {
                    ++resolved;
                    if (resolved === promises.length && allDone.status === Promise.UNFULFILLED) {
                        var results = promises.map(function (p) {
                            return p.result;
                        });
                        allDone.resolve(results);
                    }
                }).fail(function (e) {
                            if (allDone.status === Promise.UNFULFILLED)
                                allDone.reject(e); //TODO 此处i是无用的,怎么指示是哪一个promise的信息?
                        }).progress(function (v) {
                            if (allDone.status === Promise.UNFULFILLED) {
                                allDone.notify(v); //TODO 此处i是无用的,怎么指示是哪一个promise的信息?
                            }
                        });
            }
            return allDone;
        };
    
        Promise.UNFULFILLED = 0;
        Promise.RESOLVED = 1;
        Promise.REJECTED = 2;
        return Promise;
    })();
    
    var Deferred = (function (_super) {
        //继承原型
        __extends(Deferred, _super);
        function Deferred() {
            //继承
            _super.call(this);
            //成功的列表;
            this._onDones = null;
            //失败的列表;
            this._onFails = null;
            //进度的回调列表;
            this._onProgresses = null;
            // 0 : 为解决, 1 : 已解决, 2 : 被拒绝了;
            this._status = Promise.UNFULFILLED;
            this._result = undefined;
            if (Deferred._DEBUG) {
                try  {
                    throw new Error('Deferred constructor calling stack');
                } catch (e) {
                    this._stack = e;
                };
            };
        };
    
        //直接通过访问_status也行;
        Object.defineProperty(Deferred.prototype, "status", {
            get: function () {
                return this._status;
            },
            enumerable: true,
            configurable: true
        });
    
        //直接访问实例的_result也行;
        Object.defineProperty(Deferred.prototype, "result", {
            get: function () {
                return this._result;
            },
            enumerable: true,
            configurable: true
        });
    
        //把callback的成功列表全部压栈;
        Deferred.prototype.done = function (onDone) {
            if (this._status == Promise.UNFULFILLED) {
                this._onDones = this._onDones || [];
                this._onDones.push(onDone);
            //如果已经成功直接触发成功回调, (这里要注意有种情况是“已经失败”的姿态, 这个成功回调并不会入栈或者触发);
            } else if (this._status == Promise.RESOLVED)
                this._emitEventDirectly(onDone);
            return this;
        };
    
        //把callback的失败列表全部压栈;
        Deferred.prototype.fail = function (onFail) {
            if (this._status == Promise.UNFULFILLED) {
                this._onFails = this._onFails || [];
                this._onFails.push(onFail);
                //如果已经失败直接触发失败回调;
            } else if (this._status == Promise.REJECTED)
                this._emitEventDirectly(onFail);
            return this;
        };
    
        Deferred.prototype.progress = function (onProgress) {
            if (this._status == Promise.UNFULFILLED) {
                this._onProgresses = this._onProgresses || [];
                this._onProgresses.push(onProgress);
            }
            return this;
        };
    
        //then这个很重要, 他会重新返回包装后的延迟对象, 也是延迟对象里面比较复杂的东西;
        //功过then可以实现链式调用, 实例如下:
        /*
        var df = new Deferred();
        df.then(function() {
            return 1
        }).then(function(arg) {
            console.log(arg); 
            return 2;
        }).then(function(arg){
            console.log(arg)
        });
        df.resolve();
    */
        Deferred.prototype.then = function (onDone, onFail) {
            var _this = this;
            var def = new Deferred();
            var result;
    
            //then返回的是新的延迟对象
            //done是为当前这个延迟对象添加延迟对象;
            this.done(function (data) {
                // 这个done很重要, 有三个判断;
                // 如果有没有onDone就直接为当前的resolve; 一个旧的derffer被resolve了那么新的deferred也resovle, resolve的参数为旧deferred的参数:实例如下
                /*
                    var df = new Deferred();
                    df.then().done(function(arg){
                        console.log(arg);
                    });
                    df.resolve("1");
                */
    
                // 如果有onDone, onDone的返回是非Deferred对象,通过resolve(返回值)闭包内的Deferred对象, 实例如下:
                /*
                    var df = new Deferred();
                    df.then(function() {return 2}).done(function(arg){
                        console.log(arg);
                    });
                    df.resolve();
                */
    
                // 如果有onDone, 而且onDone返回对象是Promise的实例, 那么为返回的这个promise添加一个onDone, 这个onDone添加闭包内部的promise对象的resolve, 实例如下:
                /*  
                    var df = new Deferred();
                    df.then(function() { 
                        var closureDf = new Deferred();
                        setTimeout(function(){ 
                            closureDf.resolve("haha") 
                        },4000); 
                        return closureDf.promise(); 
                    }).done(function(arg){
                        console.log(arg);
                    });
                    df.resolve();
                    
                */
                if (onDone) {
                    try  {
                        result = onDone(data);
                        //主要是起到提示的作用;
                        _this._warnReturnValue(result);
                        if (result instanceof Promise) {
                            //result又是一个延迟对象的话, 当result发生resolve的时候,def也reslove
                            //result.done(def.resolve.bind(this)).fail(def.reject.bind(this)).progress(def.notify.bind(this));
                            //result.done(function(arg){ def.resolve(arg) }).fail(function(arg){ def.reject(arg) })
                            def._bindTo(result);
                            //
                            return result;
                        } else
                            //最好不要延迟对象套延迟对象, 会晕;
                            def.resolve(result);
                    } catch (err) {
                        def.reject(err);
                    }
                } else
                    def.resolve(data);
            });
            this.fail(function (err) {
                if (onFail) {
                    try  {
                        result = onFail(err);
                        _this._warnReturnValue(result);
                        if (result instanceof Promise) {
                            def._bindTo(result);
                            return result;
                        } else {
                            def.resolve(result);
                        }
                    } catch (err2) {
                        def.reject(err2);
                    }
                } else
                    def.reject(err);
            });
    
            return def;
        };
    
        Deferred.prototype.resolve = function (data) {
            if (typeof data === 'undefined')
                console.warn('>>>> Deferred.resolve() received undefined, likely a bug');
            return this._emitEvent(data, Promise.RESOLVED);
        };
    
        Deferred.prototype.reject = function (err) {
            if (Deferred._DEBUG) {
                try  {
                    throw new Error('Deferred.reject calling stack');
                } catch (e) {
                    logw('rejected: Defered.constructor stack:
    ' + (this._stack['stack'] || this._stack) + '
    rejected: Defered.rejected stack:
    ' + (e['stack'] || e) + '
    rejected: reason stack:
    ' + (err['stack'] || err));
                }
            }
            return this._emitEvent(err, Promise.REJECTED);
        };
    
        Deferred.prototype.notify = function (data) {
            return this._emitEvent(data);
        };
    
        //这个是触发事件的装饰者, 你要触发失败回调, 成功回调, 进度回调都需要走这边, 只是穿进来的姿态不一样而已;
        Deferred.prototype._emitEvent = function (data, status) {
            if (this._status != Promise.UNFULFILLED) {
                throw Error('fulfilled');
            }
    
            var callbacks;
            //处理事件列表;
            if (status === Promise.RESOLVED)
                callbacks = this._onDones;
            else if (status === Promise.REJECTED)
                callbacks = this._onFails;
            else
                callbacks = this._onProgresses;
    
            //没有status是onProgress的情况;
            if (status) {
                this._status = status;
                this._result = data;
                this._onDones = this._onFails = this._onProgresses = null;
            };
    
            if (callbacks) {
                for (var i = 0; i < callbacks.length; i++) {
                    try  {
                        //这个是执行回调列表, 是线性的;
                        callbacks[i](data);
                    } catch (e) {
                        this._log(e);
                    }
                }
            }
            return this;
        };
    
        Deferred.prototype._bindTo = function (p) {
            p.done(this.resolve.bind(this)).fail(this.reject.bind(this)).progress(this.notify.bind(this));
        };
    
        Deferred.prototype._emitEventDirectly = function (callback) {
            var _this = this;
            if (!callback)
                return;
            setTimeout(function () {
                try  {
                    callback(_this._result);
                } catch (e) {
                    _this._log(e);
                }
            }, 0);
        };
    
        Deferred.prototype._log = function (err) {
            console.warn(err.stack || err);
        };
    
        Deferred.prototype._warnReturnValue = function (value) {
            if (typeof value === 'undefined')
                console.warn('>>>> Promise.then(): onDone/onFail returns undefined, likely a bug');
            else if (value && !(value instanceof Promise) && typeof value.then === 'function')
                console.warn('>>>> Promise.then(): onDone/onFail returns a promise-like object, likely a bug. Consider Promise.wrap().');
        };
        Deferred._DEBUG = false;
        return Deferred;
    })(Promise);
    
    
    //使用方法:
    var df = new Deferred();
    df.then(function() {
        return 1
    }).then(function(arg) {
        console.log(arg); 
        return 2;
    }).then(function(arg){
        console.log(arg)
    });
    df.resolve();
    
    //单纯的Deferred相对于一个callbacks, 使用then方法就变成了链式调用(个人理解);
    var df = new Deferred();
    df.then().done(function(arg){
        console.log(arg);
    });
    df.resolve("1");
    
    //欢迎拍砖;
    var df = new Deferred();
    df.then(function() {return 2}).done(function(arg){
        console.log(arg);
    });
    df.resolve();
    </script>
    </body>
    </html>

       jQ1.7的延迟对象, 代码量比较少, 依赖callbacks,不太好懂, 慢慢看,参考jQ的延迟对象分析: http://www.cnblogs.com/snandy/archive/2012/12/19/2812935.html

     

       要先弄懂callbacks这个方法, 才能在弄懂Deferred,  when也只是一个Deferred的包装。 建议先看1.5版本的Deferred, 弄懂了再看1.7的Deferred, 下面的Deferred被我单独裁出来了,可以单独运行, 里面的注释是博客园的好像是aaron写的代码解析, 辅助大家看一下:

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
    </head>
    <body>
    <script>
    //jQ部分的延迟对象截取;
    jQuery = $ = {};
    jQuery.extend = function() {
        var options, name, src, copy, copyIsArray, clone,
                target = arguments[0] || {},
                i = 1,
                length = arguments.length,
                deep = false;
    
        // Handle a deep copy situation
        if ( typeof target === "boolean" ) {
            deep = target;
            target = arguments[1] || {};
            // skip the boolean and the target
            i = 2;
        }
    
        // Handle case when target is a string or something (possible in deep copy)
        if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
            target = {};
        }
    
        // extend jQuery itself if only one argument is passed
        if ( length === i ) {
            target = this;
            --i;
        }
    
        for ( ; i < length; i++ ) {
            // Only deal with non-null/undefined values
            if ( (options = arguments[ i ]) != null ) {
                // Extend the base object
                for ( name in options ) {
                    src = target[ name ];
                    copy = options[ name ];
    
                    // Prevent never-ending loop
                    if ( target === copy ) {
                        continue;
                    }
    
                    // Recurse if we're merging plain objects or arrays
                    if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                        if ( copyIsArray ) {
                            copyIsArray = false;
                            clone = src && jQuery.isArray(src) ? src : [];
    
                        } else {
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }
    
                        // Never move original objects, clone them
                        target[ name ] = jQuery.extend( deep, clone, copy );
    
                        // Don't bring in undefined values
                    } else if ( copy !== undefined ) {
                        target[ name ] = copy;
                    }
                }
            }
        }
    
        // Return the modified object
        return target;
    };
    
    var optionsCache = {};
    var core_rspace = /s+/;
    var core_toString = Object.prototype.toString;
    var class2type = {};
    jQuery.each = function( obj, callback, args ) {
        var name,
                i = 0,
                length = obj.length,
                isObj = length === undefined || jQuery.isFunction( obj );
    
        if ( args ) {
            if ( isObj ) {
                for ( name in obj ) {
                    if ( callback.apply( obj[ name ], args ) === false ) {
                        break;
                    }
                }
            } else {
                for ( ; i < length; ) {
                    if ( callback.apply( obj[ i++ ], args ) === false ) {
                        break;
                    }
                }
            }
    
            // A special, fast, case for the most common use of each
        } else {
            if ( isObj ) {
                for ( name in obj ) {
                    if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
                        break;
                    }
                }
            } else {
                for ( ; i < length; ) {
                    if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
                        break;
                    }
                }
            }
        };
        return obj;
    };
    $.isFunction = function( obj ) {
        return jQuery.type(obj) === "function";
    }
    $.type = function( obj ) {
        return obj == null ?
                String( obj ) :
                class2type[ core_toString.call(obj) ] || "object";
    };
    jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
        class2type[ "[object " + name + "]" ] = name.toLowerCase();
    });
    // Convert String-formatted options into Object-formatted ones and store in cache
    function createOptions( options ) {
        var object = optionsCache[ options ] = {};
        jQuery.each( options.split( core_rspace ), function( _, flag ) {
            object[ flag ] = true;
        });
        return object;
    };
    //$.Callbacks( 'once memory unique stopOnFalse'  );
    jQuery.Callbacks = function( options ) {
        // Convert options from String-formatted to Object-formatted if needed
        // (we check in cache first)
        options = typeof options === "string" ?
                ( optionsCache[ options ] || createOptions( options ) ) :
                jQuery.extend( {}, options );
    
        var // Last fire value (for non-forgettable lists)
                memory,
        // Flag to know if list was already fired
                fired,
        // Flag to know if list is currently firing
                firing,
        // First callback to fire (used internally by add and fireWith)
                firingStart,
        // End of the loop when firing
                firingLength,
        // Index of currently firing callback (modified by remove if needed)
                firingIndex,
        // Actual callback list
                list = [],
        // Stack of fire calls for repeatable lists
                stack = !options.once && [],
        // Fire callbacks
                fire = function( data ) {
                    //如果有memory我们会把传进来的参数保存;
                    memory = options.memory && data;
                    //触发的标志;
                    fired = true;
                    //如果有memory的callback对象执行过了, 会有firingStart;
                    firingIndex = firingStart || 0;
                    firingStart = 0;
                    firingLength = list.length;
                    //callback已经触发过后的标志;
                    firing = true;
                    for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                        //return false的时候就不走了
                        if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
                            memory = false; // To prevent further calls using add
                            break;
                        }
                    };
                    firing = false;
                    if ( list ) {
                        if ( stack ) {
                            if ( stack.length ) {
                                fire( stack.shift() );
                            }
                        } else if ( memory ) {
                            list = [];
                        } else {
                            self.disable();
                        }
                    }
                },
        //通过闭包, 保存局部变量, 返回self;
        // Actual Callbacks object
                self = {
                    // Add a callback or a collection of callbacks to the list
                    add: function() {
                        if ( list ) {
                            // First, we save the current length
                            var start = list.length;
    
                            // 如果传进来的是[fn, fn1, fn2 , [fn3, fn4, fn5, fn6]]会把数组扁平化哦
                            // Array.prototype.concat.apply([],[1,2,3,[4,5]]); 你懂得....;
                            (function add( args ) {
                                jQuery.each( args, function( _, arg ) {
                                    //
                                    if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) {
                                        list.push( arg );
                                    } else if ( arg && arg.length ) {
                                        // Inspect recursively
                                        add( arg );
                                    }
                                });
                            })( arguments );
                            // Do we need to add the callbacks to the
                            // current firing batch?
                            // 对定制选项的额外处理;
                            if ( firing ) {
                                firingLength = list.length;
                                // With memory, if we're not firing then
                                // we should call right away
                            } else if ( memory ) {
                                firingStart = start;
                                fire( memory );
                            }
                        }
                        return this;
                    },
                    // Remove a callback from the list
                    remove: function() {
                        //没list就不玩了;
                        if ( list ) {
                            jQuery.each( arguments, function( _, arg ) {
                                var index;
                                while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
                                    list.splice( index, 1 );
                                    // Handle firing indexes
                                    // 对定制选项的额外处理;
                                    if ( firing ) {
                                        if ( index <= firingLength ) {
                                            firingLength--;
                                        }
                                        if ( index <= firingIndex ) {
                                            firingIndex--;
                                        }
                                    }
                                }
                            });
                        }
                        return this;
                    },
                    // Control if a given callback is in the list
                    has: function( fn ) {
                        return jQuery.inArray( fn, list ) > -1;
                    },
                    // Remove all callbacks from the list
                    empty: function() {
                        list = [];
                        return this;
                    },
                    // Have the list do nothing anymore
                    disable: function() {
                        list = stack = memory = undefined;
                        return this;
                    },
                    // Is it disabled?
                    disabled: function() {
                        return !list;
                    },
                    // Lock the list in its current state
                    lock: function() {
                        stack = undefined;
                        if ( !memory ) {
                            self.disable();
                        }
                        return this;
                    },
                    // Is it locked?
                    locked: function() {
                        return !stack;
                    },
                    // Call all callbacks with the given context and arguments
                    fireWith: function( context, args ) {
                        args = args || [];
                        args = [ context, args.slice ? args.slice() : args ];
                        if ( list && ( !fired || stack ) ) {
                            if ( firing ) {
                                stack.push( args );
                            } else {
                                fire( args );
                            }
                        }
                        return this;
                    },
                    // Call all the callbacks with the given arguments
                    fire: function() {
                        self.fireWith( this, arguments );
                        return this;
                    },
                    // To know if the callbacks have already been called at least once
                    fired: function() {
                        return !!fired;
                    }
                };
    
        return self;
    };
    
    //接着, 来参考一下jQ的延迟对象 , 原文地址在:http://www.cnblogs.com/lovesueee/archive/2012/10/18/2730287.html;
    jQuery.extend({
    
        Deferred: function( func ) {
            // 数据元组集
            // 每个元组分别包含一些与当前deferred相关的信息:
            // 分别是:触发回调函数列表执行(函数名),添加回调函数(函数名),回调函数列表(jQuery.Callbacks对象),deferred最终状态(第三组数据除外)
            // 总体而言,三个元组会有对应的三个callbacklist对应于doneList, failList, processList
            // 对于jQuery.Callbacks对象,可以看之前的文章http://www.cnblogs.com/lovesueee/archive/2012/10/18/2729829.html
            var tuples = [
                        // action, add listener, listener list, final state
                        [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
                        [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
                        [ "notify", "progress", jQuery.Callbacks("memory") ]
                    ],
            // deferred的状态,分为三种:pending(初始状态), resolved(解决状态), rejected(拒绝状态)
                    state = "pending",
            // promise对象,主要有两点作用:
            // 1. 在初始化deferred对象时,promise对象里的方法都会被extend到deferred中去
            // 2. 那么,生成的deferred对象里必然引用了promise对象的promise方法,所以当调用deferred.promise()时,
            //    deferred对象会通过闭包返回promise对象,这就是所谓的受限制的deferred对象(用deferred2表示),因为相比之前,
            //    返回的deferred2不在拥有resolve(With), reject(With), notify(With)这些能改变deferred对象状态并且执行callbacklist的方法了
                    promise = {
    
                        // 返回闭包里的内部state(外部只读)
                        state: function() {
                            return state;
                        },
    
                        // 同时在doneList和failList的list里添加回调函数(引用)
                        // 那么不论deferred最终状态是resolved还是rejected, 回调函数都会被执行,这就是所谓的always
                        always: function() {
                            deferred.done( arguments ).fail( arguments );
                            return this;
                        },
    
                        // jQuery.then()会创建一个新的受限制的deferred对象
                        // 有点复杂,下面我有画一个图帮忙理解
                        then: function( /* fnDone, fnFail, fnProgress */ ) {
                            var fns = arguments;
                            // 创建新的受限制的deferred对象(称作newDeferrred),并返回
                            // 利用返回的deferred对象就可以做很多事了,你懂的
                            return jQuery.Deferred(function( newDefer ) {
                                /*
                                 var tuples = [
                                 // action, add listener, listener list, final state
                                 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
                                 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
                                 [ "notify", "progress", jQuery.Callbacks("memory") ]
                                 ]
                                 */
                                jQuery.each( tuples, function( i, tuple ) {
                                    var action = tuple[ 0 ],
                                            fn = fns[ i ];
                                    // >>>> 很重要的一点就是:then这个方法是新建一个deferred,然后把当前deferred的done, fail progress三个依次添加新deferred, 并把这个deferred返回; <<<<
    
                                    // deferred[ done | fail | progress ] for forwarding actions to newDefer
                                    // 分别为deferred的三个callbacklist添加回调函数,根据fn的是否是函数,分为两种情况:
                                    // 1.不是函数的情况(如值为undefined或者null等),直接链接到newDeferred的resolve(reject,notify)方法,也就是说
                                    //   newDeferrred的执行依赖外层的调用者deferred的状态或者说是执行动作(resolve还是reject或者是notify)
                                    //   此时deferred.then()相当于将自己的callbacklist和newDeferred的callbacklist连接起来了,故可以在newDeferred
                                    //   中大做文章
                                    // 2.是函数的情况,根据返回值(称作returnReferred)是否是deferred对象,又可以分为两种情况:
                                    //   2.1 返回值是deferred对象,那么在returnReferred对象的三个回调函数列表中添加newDeferred的resolve(reject,notify)方法
                                    //       也就是说newDeferrred的执行依赖returnDeferred的状态
                                    //   2.2 返回值不是deferred对象,那么将返回值returned作为newDeferred的参数并将从外层deferred那边的上下文环境作为newDeferred
                                    //       的执行上下文,然后执行对应的回调函数列表,此时newDeferrred的执行依赖外层的调用者deferred的状态
    
                                    //deferred.done(fn), deferred.fail(fn), deferred.progress(fn);
                                    deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
                                        //传进来的是函数的情况下, 函数可能不返回, 也可能返回一个延迟对象;;
                                            function() {
                                                //这行传进来的参数, 利用闭包, fn是这个闭包的变量;
                                                var returned = fn.apply( this, arguments );
                                                //又返回了一个延迟对象的话, 我们再把这个新的延迟对象的resolve和reject和notify放到这个deferred;
                                                if ( returned && jQuery.isFunction( returned.promise ) ) {
                                                    returned.promise()
                                                            .done( newDefer.resolve )
                                                            .fail( newDefer.reject )
                                                            .progress( newDefer.notify );
                                                } else {
                                                    //这个函数返回的不是延迟对象, 把这个fn的返回值作为参数触发newDefer;
                                                    newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
                                                }
                                            } :
                                            newDefer[ action ]
                                    );
                                });
                                fns = null;
                            }).promise();
                        },
    
                        promise: function( obj ) {
                            return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise;
                        }
                    },
            // 实际返回的deferred对象
                    deferred = {};
    
            // Keep pipe for back-compat
            // pipe和then引用同一个函数,所以功能是一样的
            // 只不过通常的用法是:会用pipe进行filter操作
            promise.pipe = promise.then;
    
            // Add list-specific methods
            // 通过上面定义的数据元组集来扩展一些方法
            jQuery.each( tuples, function( i, tuple ) {
                //就是callback了;
                var list = tuple[ 2 ],
                //resolved, rejected
                        stateString = tuple[ 3 ];
    
                // promise[ done | fail | progress ] = list.add
                // 给上面的promise对象添加done,fail,process方法
                // 这三个方法分别引用三个不同jQuery.Callbacks对象的add方法(不是同一个引用),
                // 那么这三个方法的用途就是向各自的回调函数列表list(各自闭包中)中添加回调函数,互不干扰
                promise[ tuple[1] ] = list.add;
    
                // Handle state
                // 通过stateString有值这个条件,预先向doneList,failList中的list添加三个回调函数
                // doneList : [changeState, failList.disable, processList.lock]
                // failList : [changeState, doneList.disable, processList.lock]
                // changeState 指的是下面首先添加的一个改变deferred对象的匿名函数
                // 可以看的出: 不论deferred对象最终是resolve(还是reject),在首先改变对象状态之后,都会disable另一个函数列表failList(或者doneList)
                // 然后lock processList保持其状态,最后执行剩下的之前done(或者fail)进来的回调函数
                // 当然了,上述情况processList除外
                if ( stateString ) {
                    // 一旦触发就会把这个闭包的姿态字符串保存的state里面去;
                    list.add(function() {
                        // state = [ resolved | rejected ]
                        state = stateString;
    
                        // [ reject_list | resolve_list ].disable; progress_list.lock
                    }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
                }
    
                // deferred[ resolve | reject | notify ] = list.fire
                // 给deferred对象添加resolve(With), reject(With), notify(With)方法
                // 这三个方法分别引用三个不同jQuery.Callbacks对象的fire方法;
                deferred[ tuple[0] ] = list.fire;
                deferred[ tuple[0] + "With" ] = list.fireWith;
            });
    
            // jQuery.extend( deferred, promise );
            // 将上面的promise对象extend进deferred中
            promise.promise( deferred );
    
            // Call given func if any
            // 如果调用jQuery.Deferred(func)指定了参数,那么调用func并设置func的上下文和参数均为deferred
            // 在jQuery.then()中有用到这一点
            if ( func ) {
                func.call( deferred, deferred );
            }
    
            // All done!
            // 返回最终的deferred对象
            return deferred;
        },
    
        //suborinate:部属;部下,下级的意思,
        when: function( subordinate /* , ..., subordinateN */ ) {
            var i = 0,
            // 首先将arguments伪数组转换为真正的数组
                    resolveValues = core_slice.call( arguments ),
                    length = resolveValues.length,
    
            // the count of uncompleted subordinates
            // jQuery.isFunction( subordinate.promise )用来判断subordinate是否是deferred对象
            // 1. 在参数个数等于1的情况下:
            //   1.1 如果参数是deferred对象,那么remaining = length, 这是remaining就是1嘛
            //   1.2 否则remaining为0
            // 2. 在参数不等于1(即等于0或者大于1)的情况:remaining = length
                    remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
    
            // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
            // 到这里就可以知道:如果参数个数仅为1个,并且是deferred对象,那么就无需再生成deferred对象
                    deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
    
            // Update function for both resolve and progress values
                    updateFunc = function( i, contexts, values ) {
                        // 这里返回一个函数作为一个callback完全是为了创建一个闭包,主要是为了保持i的值
                        return function( value ) {
                            // 保存各个deferred执行的上下文,也就是说之后whenDeferred的回调函数的上下文就是一个数组
                            contexts[ i ] = this;
                            // 保存各个deferred执行时的参数,之后传递给whenDeferred的回调函数
                            // 此时values的值有原先的jQuery.when()传进来的参数变为各个deferred执行回调时的参数了,也就是说覆盖了
                            values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
                            if( values === progressValues ) {
                                deferred.notifyWith( contexts, values );
                                //所有的defer都执行了以后remaining就等于0了;
                            } else if ( !( --remaining ) ) {
                                // 时机成熟,即所有延迟都resolve,执行whenDeferred的回调函数
                                deferred.resolveWith( contexts, values );
                            }
                        };
                    },
    
                    progressValues, progressContexts, resolveContexts;
    
            // add listeners to Deferred subordinates; treat others as resolved
            // 如果参数个数大于1,那么就是说有可能存在多个deferred对象
            // 这时需要一些条件判断以保证是所有的deferred对象都resolve了,再执行whenDeferred的resolve
            // 或者当有一个deferred对象reject了,whenDeferred的reject
            if ( length > 1 ) {
                progressValues = new Array( length );
                progressContexts = new Array( length );
                resolveContexts = new Array( length );
                for ( ; i < length; i++ ) {
                    // 如果是deferred对象, 为每一个promise添加update,失败就执行返回deferred的fail列表;
                    if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
                        // 给每个参数(deferred对象)添加最后的回调,用来检查此时的状态
    
                        resolveValues[ i ].promise()
                            // 用于当每一个deferred对象resolve回来,用updateFunc返回的函数检查此时其他deferred对象的状态(即此时remaining是否等于0了)
                            //updateFunc是一个闭包, 他把i传进去了, 只有then().done()或者then().promise()有返回值, promise(),或者是done是没有返回值的;
                                .done( updateFunc( i, resolveContexts, resolveValues ) )
                            // 如果有一个deferred对象reject,whenDeferred将执行reject
                                .fail( deferred.reject )
                            //updateFunc又是一个闭包, ;
                                .progress( updateFunc( i, progressContexts, progressValues ) );
                        // 如果不是deferred对象,直接--remaining,视为resolve
                    } else {
                        --remaining;
                    };
                };
            };
    
            // if we're not waiting on anything, resolve the master
            // 如果此时remaining就等与0了,表示没有什么延迟需要等待,那么立即之行whenDeferred的resolveWith
            // 此时resolveContexts为undefined, 这就意味这上下文将为全局的window
            if ( !remaining ) {
                deferred.resolveWith( resolveContexts, resolveValues );
            }
    
            // 返回promise对象;
            return deferred.promise();
        }
    });
    
    var df = $.Deferred();
    df.done(function(arg){
        console.log(arg);
        console.log(1)
    })
    df.done(function(arg){
        console.log(arg);
        console.log(2)
    });
    df.resolve("Deffffffffffrrrrred");
    
    //延迟对象pipe的使用, pipe和then是一样的, 指向同一个函数;
    var df = $.Deferred();
    df.pipe(function() {
        var closureDf = $.Deferred();
        setTimeout(function(){
            closureDf.resolve("haha")
        },4000);
        console.log(closureDf);
        return closureDf;
    }).done(function(arg){alert(1)
                console.log(arg);
            });
    df.resolve();
    
    </script>
    </body>
    </html>

       ES6原生的好像支持PROMISE么么哒,O(∩_∩)O哈哈~;

      
    参考链接:
      用法:
        阮一峰的jQuery.Deferred对象: http://javascript.ruanyifeng.com/jquery/deferred.html

      Aaron:

        Aaron深入分析延迟对象:http://www.cnblogs.com/aaronjs/p/3356505.html

        Aaron  分析 Deferred概念 :http://www.cnblogs.com/aaronjs/p/3348569.html
      github:
        when的主页: https://github.com/cujojs/when/
        延迟对象cho45: https://github.com/cho45/jsdeferred
      学习实例:
        whenJS的使用方法,来自蛐蛐的个人博客:https://www.imququ.com/post/promises-when-js.html
        教你一步一步实现一个Promise:http://www.cnblogs.com/ygm125/p/3735677.html
      百科:
        promise规范A+: https://promisesaplus.com/
        维基百科的promise/A规范说明:http://wiki.commonjs.org/wiki/Promises/A  ,打开非常慢
        维基百科的promise/B规范说明:http://wiki.commonjs.org/wiki/Promises/B ,打开也非常慢

      

  • 相关阅读:
    vue与laravel
    php artisan 命令
    HTTP 状态码
    PhpStorm提高效率的使用方法及设置
    好RESTful API的设计原则
    laravel 入门基础之安装
    c++ sizeof(字符数组)
    new delete/delete[] 测试
    linux g++ 查找动态链接库
    linux下定时器耗时研究
  • 原文地址:https://www.cnblogs.com/diligenceday/p/4237779.html
Copyright © 2020-2023  润新知