由于1.7版本后$.Callbacks从Deferred中抽离出去了,目前版本的Deferred.js代码不过150行,而真正$.Deferred的实现只有100行左右,实现的逻辑是相当犀利的。
因为Callback被剥离出去后,整个Deferred就显得非常的精简,代码直接通过extend扩展到静态接口上,对于extend的继承这个东东,在之前就提及过jQuery如何处理内部jQuery与init相互引用this的问题,所以当jQuery.extend只有一个参数的时候,其实就是对jQuery静态方法的一个扩展。
jQuery.extend({ Deferred:function(func){ ...省略代码.... return deferred }, when:function(func){ ...省略代码.... return deferred.promise(); } })
我们来具体看看2个静态方法内部都干了些什么?
Deferred整体结构:右边代码所示。
Deferred就是一个简单的工厂方法,有两种方式使用:
var a = $.Deferred() $.Deferred(function(){})
内部其实是严重依赖$.Callbacks对象,Callbacks就是用来储存deferred依赖的数据的。
因为done、fail、progress就是jQuery.Callbacks("once memory")所有对应的处理:
var list = jQuery.Callbacks("once memory") promise['done'] = list.add;
deferred定义了一系列的接口,堪称一绝,100多行的代码,精练的有些过分。
Deferred方法内部建议了2个对象,一个是deferred外部接口对象,一个是内部promise对象。
promise对象解释是一个受限的对象, 这就是所谓的受限制的deferred对象,因为相比之前, 返回的deferred不再拥有resolve(With), reject(With), notify(With)这些能改变deferred对象状态并且执行callbacklist的方法了,只能是then、done、fali等方法。
其内部通过tuples数组,存储了所有的接口API,通过遍历把所有的接口一次都挂到内部promise与deferred对象上。
其中定义了done、fail以及progress这几个方法,其实就是Callbacks回调函数中的add方法,用与push外部的的数据,保存在队列上。
我们通过resolve、reject以及notify其实也就是处理Callbacks中的队列列表。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <script src="http://code.jquery.com/jquery-latest.js"></script> <title></title> </head> <body> <script type="text/javascript"> // jQuery. Deferred主要处理: // 显而易见Deferred是个工厂类,返回的是内部构建的deferred对象 // tuples 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态 // 创建了一个promise对象,具有state、always、then、primise方法 // 扩展primise对象生成最终的Deferred对象,返回该对象 // primise对象就是一个受限对象,只读 var Deferred = function(func) { var tuples = [ //1 动作 //2 侦听器 //3 最终状态 //后面的操作将是围绕这些接口处理 ["resolve", "done", jQuery.Callbacks("once memory"), "resolved"], ["reject", "fail", jQuery.Callbacks("once memory"), "rejected"], ["notify", "progress", jQuery.Callbacks("memory")] ], state = "pending", //扩展的primise对象 promise = { state: function() {}, always: function() {}, then: function( /* fnDone, fnFail, fnProgress */ ) {}, promise: function(obj) {} }, deferred = {}; //定义管道风格的接口pipe promise.pipe = promise.then; //逐个添加所有的接口到deferred对象上 jQuery.each(tuples, function(i, tuple) { deferred[tuple[0]] = function() { deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments); return this; }; deferred[tuple[0] + "With"] = list.fireWith; }); //转成成promise对象 promise.promise(deferred); //如果传递的参数是函数,直接运行 if (func) { func.call(deferred, deferred); } return deferred; } //when就是一个合集的处理 //可以收集多个异步操作,合并成功后处理 //同时也可以绑定Promise 对象的其它方法,如 defered.then //所以when内部必须要创建一个deferred对象 var when = function(subordinate /* , ..., subordinateN */ ) { var i = 0, resolveValues = slice.call(arguments), length = resolveValues.length, deferred = remaining === 1 ? subordinate : jQuery.Deferred(), updateFunc = function(i, contexts, values) { return function(value) {}; }, progressValues, progressContexts, resolveContexts; if (length > 1) { progressValues = new Array(length); progressContexts = new Array(length); resolveContexts = new Array(length); for (; i < length; i++) { if (resolveValues[i] && jQuery.isFunction(resolveValues[i].promise)) { resolveValues[i].promise() .done(updateFunc(i, resolveContexts, resolveValues)) .fail(deferred.reject) .progress(updateFunc(i, progressContexts, progressValues)); } else { --remaining; } } } return deferred.promise(); } </script> </body> </html>