jquery中的 deferred之 then (二)

例:

var def = $.Deferred();
            var prs1 = def.then(function (val) {
                var result = val + "_123"
                console.log(result);// 0_123
                return result;;
            });
            var prs2 = prs1.then(function (val) {
                var result = val + "_234"
                console.log(result);// 0_123_234
                return result;
            });
            var prs3 = prs2.then(function (val) {
                var result = val + "_345"
                console.log(result);// 0_123_234_345
                return result;
            });
            def.resolve("0");

核心源码分析:

then: function( /* fnDone, fnFail, fnProgress */ ) {
                    var fns = arguments;
                    return jQuery.Deferred(function (newDefer) { //20170620 huanhua 当调用 jQuery.Deferred(参数)  参数不为空的时候,参数必须是 包含 $.Deferred()对象参数的函数
                                                                  //if ( func ) { func.call( deferred, deferred );} 详见下面这段代码。
                        jQuery.each(tuples, function (i, tuple) {
                            var action = tuple[ 0 ],
                                fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
                            // deferred[ done | fail | progress ] for forwarding actions to newDefer
                            deferred[ tuple[1] ](function() {
                                var returned = fn && fn.apply(this, arguments);
                                //20170620 huanhua 如果then方法传递的参数 [fnDone, fnFail, fnProgress],其中的函数如果返回的是 Defferred对象。
                                if (returned && jQuery.isFunction(returned.promise)) {
                                    //20170620 huanhua 此时注册的 done/fail/progess 就是传入的 Defferred对象已经注册好了的对象
                                    //20170624 huahua returned是一个 deferred,在 fn 里面,必须要调用 deferred.resolve/deferred.reject/deferred.notify
                                    //否则不会 触发 newDefer.resolve/newDefer.reject/newDefer.notify
                                    returned.promise()
                                        .done( newDefer.resolve )
                                        .fail( newDefer.reject )
                                        .progress( newDefer.notify );
                                } else {
                                    newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
                                }
                            });
                        });
                        fns = null;
                    }).promise();
                },

里面最核心的一段代码,如下这段代码能看懂基本就看懂了 then了:

deferred[ tuple[1] ](function() {
                                var returned = fn && fn.apply(this, arguments);
                                //20170620 huanhua 如果then方法传递的参数 [fnDone, fnFail, fnProgress],其中的函数如果返回的是 Defferred对象。
                                if (returned && jQuery.isFunction(returned.promise)) {
                                    //20170620 huanhua 此时注册的 done/fail/progess 就是传入的 Defferred对象已经注册好了的对象
                                    //20170624 huahua returned是一个 deferred,在 fn 里面,必须要调用 deferred.resolve/deferred.reject/deferred.notify
                                    //否则不会 触发 newDefer.resolve/newDefer.reject/newDefer.notify
                                    returned.promise()
                                        .done( newDefer.resolve )
                                        .fail( newDefer.reject )
                                        .progress( newDefer.notify );
                                } else {
                                    newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
                                }
                            });

首先我们看一个案例:

var Person = function () {
                var listdo = [];
                var parValue = "";
                this.fire = function (value) {
                    parValue = value;
                    for (var xh in listdo) {
                        listdo[xh](value);
                    }
                };
                this.do = function (fn) {
                    var prs = new Person();
                    if (typeof fn === "function") {
                        listdo.push(fn);
                    }
                    listdo.push(function () { prs.fire(parValue); });
                    return prs;
                }
            };
            var person1 = new Person();
            person1.do(function (val) { alert("孩子们:" + val); })
                .do(function (val) { alert("孙子们:" + val); })
                .do(function (val) { alert("重孙们:" + val); });
            person1.fire("操练起来!!!");

这段代码中有一个祖孙的链式关系,通过闭包来实现的,分析见图2。

图2:jquery中的 deferred之 then (二)

这个思路很重要,也是 then 实现的核心思想。

在then的源代码中有这么一段代码:

// deferred[ done | fail | progress ] for forwarding actions to newDefer
                            deferred[ tuple[1] ](function() {

deferred[tuple[1]]就是在给 deferred[done|fail|progess]添加执行的方法

newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );

这段代码就是添加的执行链式中下一个对象的方法。returned或者arguments就是传递到链式中下一个要执行的对象中的方法的参数。

如果这些都看懂了,then的实现原理就明白了,实现了一个按照 then添加的先后顺序进行执行的功能。