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:
这个思路很重要,也是 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添加的先后顺序进行执行的功能。