关于Deferred对象,建议先看一下阮一峰老师的《jQuery的deferred对象详解》

看完之后,相信你对Deferred已经有所了解,如果你还想继续阅读下面的源码,可以先自己看下jQuery.Callbacks,或者先参考我前一篇文章:《学习jQuery.Callbacks》

完后再看下面的源码注释,相信你会发现,所谓的Deferred,其实就是构建了2条Callbacks的回调list,如下:

var calresolve = $.Callbacks('once memory'),calreject  = $.Callbacks('once memory'),calnotify  = $.Callbacks('memory');var state = function(){state = stateString;
}calresolve.add(state,calreject.disable,calnotify.lock);
calreject.add(state,calresolve.disable,calnotify.lock);

当我们var def = $.Deferred()时,就已经生成了上面的两条list。我们还会发现,其实done/fail就是add,而resolve和reject就是fire。所以,当我们每次执行resolve或reject时,最少要执行3个回调,加上你新添加的回调(done||fail),分别是设置状态值state和将另一种状态禁用和锁定。这样就不会在你成功done时还能输出fail。看下面代码:

var fn1 = function(value){alert('fn1:' + value)
}
var def = $.Deferred();
def.done(fn1);              //相当于$.Callbacks('once memory').add(fn1)
def.resolve('littledu');    //相当于$.Callbacks('once memory').fire('littledu')

Deferred的原理也就大概如此。知道是怎么回事后,再重新看源码,会发现一切都很清晰。其他的api就不介绍了,直接上源码注释吧,都是个人学习理解,如果有同学看到这里,请辨证的看,不包正确,被我误导不负责任嘻嘻。

Deferred: function( func ) {//声明一个二维数组,分别存放3个状态的数组,需先了解jQuery.Callbacks。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") ]],state = "pending",   //回调状态值,分别有pending,resolved和rejectedpromise = {state: function() {return state;},always: function() {deferred.done( arguments ).fail( arguments );return this;},then: function( /* fnDone, fnFail, fnProgress */ ) {var fns = arguments;return jQuery.Deferred(function( newDefer ) {jQuery.each( tuples, function( i, tuple ) {var action = tuple[ 0 ],fn = fns[ i ];// deferred[ done | fail | progress ] for forwarding actions to newDeferdeferred[ tuple[1] ]( jQuery.isFunction( fn ) ?function() {var returned = fn.apply( this, arguments );if ( returned && jQuery.isFunction( returned.promise ) ) {returned.promise().done( newDefer.resolve ).fail( newDefer.reject ).progress( newDefer.notify );} else {newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );}} :newDefer[ action ]);});fns = null;}).promise();},// Get a promise for this deferred// If obj is provided, the promise aspect is added to the objectpromise: function( obj ) {return obj != null ? jQuery.extend( obj, promise ) : promise;}},deferred = {};  //声明deferred对象// Keep pipe for back-compatpromise.pipe = promise.then;// Add list-specific methods//jQuery.each( tuples, function( i, tuple ) {var list = tuple[ 2 ],  //保存Callbacks对象stateString = tuple[ 3 ];  //保存状态值// promise[ done | fail | progress ] = list.add// 给promise添加方法,分别为done,fail,progress,绑定对应Callbacks的add方法,相当于调用deferred对象的done,fail,progress时,都是调用其Callbacks对象的add方法。// promise.done = list.add// promise.fail = list.add// promise.progress = list.addpromise[ tuple[1] ] = list.add;// Handle state// action, add listener, listener list, final state//[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],//[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],//将状态函数等扔进队列if ( stateString ) { //stateString只有前两个数组有值,为前两个数组的Callbacks对象添加回调,均有一个存储state的匿名函数和另外两个Callbacks方法。其中第一个数组添加的是第二个数组的Callbacks对象的disable方法,第二个添加的是第一个数组的Callbacks对象的disable方法。lock方法则均为第3个数组的Callbacks对象所有//[state,reject.disable,notify.lock]//[state,resolve.disable,notify.lock]//var dfd = $.Deferred();//dfd.done(fn1) => [state,reject.disable,notify.lock,fn1]//dfd.state() => 在执行done的时候,第一个匿名函数就是设置state值的list.add(function() {// state = [ resolved | rejected ]state = stateString;// [ reject_list | resolve_list ].disable; progress_list.lock// 0^1=1 1^1=0}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );}// deferred[ resolve | reject | notify ] = list.fire// 这里,相当于deferred对象调用resolve,reject,notify时,都执行回调队列里的回调deferred[ tuple[0] ] = list.fire;deferred[ tuple[0] + "With" ] = list.fireWith;});// Make the deferred a promise// 将promise的方法推入deferred,此时promise有的deferred都有,deferred有的promise不一定有,如resolve和rejectpromise.promise( deferred );// Call given func if any// 如果jQuery.Deferred(fn)有传入函数,则会执行这里,函数的context将会是deferred,参数也是deferred,在then中有用到,也可以外部直接传入函数中使用if ( func ) {func.call( deferred, deferred );}// All done!return deferred;},// Deferred helper// when,可以理解为deferred的一个中转站,比如我有一个函数,我要在这个函数执行完后再触发回调,when就是做这样的工作,它需要这个函数返回deferred对象,然后返回的是deferred.promise对象,从而可以实现$.when(fn).done(fnDone)的链式操作,因为done其实也就是Callbacks.add,所以这里相当于fnDone这个回调push进回调数组,然后在所传的函数里面有一句resolve()或reject()执行一下回调数组,从而触发回调。就是这样。// PS:对于when我还有很多不明白,比如传多个函数,有人说要两个函数都resolve,才能执行done,但我测试回调的done或fail是以第一个函数为准的,也就是说如果它为resolve,那么回调会进入done,否则则进入fail,还有待观察when: function( subordinate /* , ..., subordinateN */ ) {var i = 0,resolveValues = core_slice.call( arguments ),  //将deferred对象转化为数组length = resolveValues.length,// the count of uncompleted subordinates// 如果length不等于1,则直接返回length,如果length==1,则要看所传的函数是不是deferred对象,如果不是返回0,是的话返回length(1)remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,// the master Deferred. If resolveValues consist of only a single Deferred, just use that.// 如果remaining==1,则说明所传函数是deferred对象,直接使用它,否则重新创建一个新的deferred对象deferred = remaining === 1 ? subordinate : jQuery.Deferred(),// Update function for both resolve and progress valuesupdateFunc = function( i, contexts, values ) {return function( value ) {contexts[ i ] = this;values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;if( values === progressValues ) {deferred.notifyWith( contexts, values );} else if ( !( --remaining ) ) {deferred.resolveWith( contexts, values );}};},progressValues, progressContexts, resolveContexts;// add listeners to Deferred subordinates; treat others as resolved// 当所传函数不止一个时,情况较复杂,这里我也是很多不明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;}}}// if we're not waiting on anything, resolve the master// 如果所传函数不是deferred对象,则立即执行回调,这里用了resolveWidth,表明执行的都是done方法,resolveContexts为undefined,表明回调执行的上下文在windowif ( !remaining ) {deferred.resolveWith( resolveContexts, resolveValues );}return deferred.promise();}

  

转载于:https://www.cnblogs.com/littledu/articles/2813051.html

学习jQuery.Deferred相关推荐

  1. jQuery.Deferred() 方法

    今天在项目中遇到了Deferred()的方法,虽然项目中使用的是dojo,但是其实各个框架都是相通的,以前都没有遇到过,所以今天就在网上找了些资料学习了一下: 定义和用法: $.Deferred() ...

  2. 学习jQuery的on事件

    开发asp.net mvc程序,多少是离不开jQuery客户程序.今天Insus.NET学习jQuery的一个on事件驱动. 先在网页视图放一个图片铵钮,用户可以使用mouse对这图片时行over,o ...

  3. 学习jQuery之旅--使用炫酷的jQuery插件

    前两篇文章中,介绍了jQuery中强大的Selectors (选择器)以及开发中比较常用的方法的使用.今天和大家一起体验一下jQuery另一个吸引人的地方--强大炫酷实用的jQuery插件. 做网站的 ...

  4. 使用 jQuery Deferred 和 Promise 创建响应式应用程序

    这篇文章,我们一起探索一下 JavaScript 中的 Deferred 和 Promise 的概念,它们是 JavaScript 工具包(如Dojo和MochiKit)中非常重要的一个功能,最近也首 ...

  5. 从零开始学习jQuery (五) 事件与事件对象【转】

    一.摘要 事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解. 二.前言 本篇文章是至今为止本系列内容最多的一篇, 足以可见其 ...

  6. 学习jQuery顺便学习下CSS选择器:奇偶匹配nth-child(even)

    原文转自:http://www.cnblogs.com/Elgin/archive/2010/05/24/1742563.html 首先解释一下两个单词,一个是odd,一个是even,这两个单词表示的 ...

  7. 从零开始学习jQuery (十一) 实战表单验证与自动完成提示插件

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  8. 从零开始学习jQuery (十) jQueryUI常用功能实战

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  9. 从零开始学习jQuery (九) jQuery工具函数

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  10. 从零开始学习jQuery (八) 插播:jQuery实施方案

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

最新文章

  1. diff 命令,防止遗忘
  2. Leetcode 74. 搜索二维矩阵 (每日一题 20210907)
  3. es6 的数组的方法
  4. 正式软件工作第一天————MVC、ext JS、和clsa
  5. FluentAspects -- 基于 Fluent API 的 Aop
  6. 一张图弄懂java线程的状态和生命周期
  7. 导航栏隐藏的正确方式
  8. QQ空间日志导出(php)
  9. 雅思阅读--读书笔记
  10. python_操作MySQL 初解 之__类方法调用并 增-删-改-查
  11. Nova API服务之Nova API服务的启动
  12. ⑤CSS浮动学成在线网实例
  13. Spring Boot 整合——Spring Boot整合kafka整合
  14. html网页添加到桌面,那个浏览器可以把网页添加到桌面
  15. 隐式图的搜索问题(九宫重排)——项目实现
  16. 使用云服务器掉线/异常/出问题是什么原因?如何解决?
  17. Day_04 Vue学习
  18. 入门学习次世代游戏3D建模,你应该弄懂这10件事情
  19. 中国国产基础软件发展的机遇与挑战
  20. Ubuntu 使用中国版 Firefox

热门文章

  1. win10虚拟机搭建Hadoop集群(已完结)
  2. PostgreSQL | 学习笔记语句汇总
  3. vmware10中开启Intel VT-x
  4. 单词的理解 —— 通过上下文环境
  5. zen-Coding
  6. 防雷探测器在建筑物中的要求
  7. 客户关系管理式的电子商务
  8. 多线程----简单的生产者和消费者
  9. 程序员之路:python3+PyQt5+pycharm桌面GUI开发
  10. JS实现类似QQ好友头像hover时显示资料卡的效果