千家信息网

如何用jQuery 2.0.3源码分析Deferred

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇文章给大家分享的是有关如何用jQuery 2.0.3源码分析Deferred,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。构建Def
千家信息网最后更新 2026年11月02日如何用jQuery 2.0.3源码分析Deferred

本篇文章给大家分享的是有关如何用jQuery 2.0.3源码分析Deferred,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

构建Deferred对象时候的流程图

**********************源码解析**********************

因为callback被剥离出去后,整个deferred就显得非常的精简

jQuery.extend({        Deferred : function(){}            when : function()   )}

对于extend的继承这个东东,在之前就提及过jquery如何处理内部jquery与init相互引用this的问题

对于JQ的整体架构一定要弄懂 http://www.cnblogs.com/aaronjs/p/3278578.html

所以当jQuery.extend只有一个参数的时候,其实就是对jQuery静态方法的一个扩展

我们在具体看看2个静态方法内部都干了些什么:

Deferred整体结构:

源码精简了部分代码

Deferred: function( func ) {          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",              promise = {                  state: function() {},                  always: function() {},                  then: function( /* fnDone, fnFail, fnProgress */ ) { },                  // Get a promise for this deferred                  // If obj is provided, the promise aspect is added to the object                  promise: function( obj ) {}              },              deferred = {};          jQuery.each( tuples, function( i, tuple ) {              deferred[ tuple[0] + "With" ] = list.fireWith;          });          promise.promise( deferred );          // All done!          return deferred;      },
  1. 显而易见Deferred是个工厂类,返回的是内部构建的deferred对象

  2. tuples 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态

  3. 创建了一个promise对象,具有state、always、then、primise方法

  4. 扩展primise对象生成最终的Deferred对象,返回该对象

这里其实就是3个处理,但是有个优化代码的地方,就是把共性的代码给抽象出来,通过动态生成了

具体源码分析:

Deferred自身则围绕这三个对象进行更高层次的抽象

  • 触发回调函数列表执行(函数名)

  • 添加回调函数(函数名)

  • 回调函数列表(jQuery.Callbacks对象)

  • deferred最终状态(第三组数据除外)

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") ]      ],

这里抽象出2组阵营:

1组:回调方法/事件订阅

done,fail,progress

2组:通知方法/事件发布

resolve,reject,notify,resolveWith,rejectWith,notifyWith

tuples 元素集 其实是把相同有共同特性的代码的给合并成一种结构,然后通过一次处理

jQuery.each( tuples, function( i, tuple ) {              var list = tuple[ 2 ],                  stateString = tuple[ 3 ];              promise[ tuple[1] ] = list.add;              if ( stateString ) {                  list.add(function() {                      state = stateString;                   // [ reject_list | resolve_list ].disable; progress_list.lock                  }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );              }              deferred[ tuple[0] ] = function() {                  deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );                  return this;              };              deferred[ tuple[0] + "With" ] = list.fireWith;          });

对于tuples的3条数据集是分2部分处理的

第一部分将回调函数存入

promise[ tuple[1] ] = list.add;

其实就是给promise赋予3个回调函数

promise.done = $.Callbacks("once memory").add
promise.fail = $.Callbacks("once memory").add
promise.progressl = $.Callbacks("memory").add

如果存在deferred最终状态

默认会预先向doneList,failList中的list添加三个回调函数

if ( stateString ) {      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 );  }

*************************************************************
这里有个小技巧

i ^ 1 按位异或运算符

所以实际上第二个传参数是1、0索引对调了,所以取值是failList.disable与doneList.disable

*************************************************************

通过stateString有值这个条件,预先向doneList,failList中的list添加三个回调函数

分别是:

doneList : [changeState, failList.disable, processList.lock]  failList : [changeState, doneList.disable, processList.lock]
  • changeState 改变状态的匿名函数,deferred的状态,分为三种:pending(初始状态), resolved(解决状态), rejected(拒绝状态)

  • 不论deferred对象最终是resolve(还是reject),在首先改变对象状态之后,都会disable另一个函数列表failList(或者doneList)

  • 然后lock processList保持其状态,最后执行剩下的之前done(或者fail)进来的回调函数

所以第一步最终都是围绕这add方法

  • done/fail/是list.add也就是callbacks.add,将回调函数存入回调对象中

第二部分很简单,给deferred对象扩充6个方法

  • resolve/reject/notify 是 callbacks.fireWith,执行回调函数

  • resolveWith/rejectWith/notifyWith 是 callbacks.fireWith 队列方法引用

最后合并promise到deferred

promise.promise( deferred );  jQuery.extend( obj, promise )

所以最终通过工厂方法Deferred构建的异步对象带的所有的方法了

return 内部的deferred对象了

由此可见我们在

var defer = $.Deferred(); //构建异步对象

的时候,内部的对象就有了4个属性方法了

  1. deferred: Object

    1. always: function () {

    2. done: function () {

    3. fail: function () {

    4. notify: function () {

    5. notifyWith: function ( context, args ) {

    6. pipe: function ( /* fnDone, fnFail, fnProgress */ ) {

    7. progress: function () {

    8. promise: function ( obj ) {

    9. reject: function () {

    10. rejectWith: function ( context, args ) {

    11. resolve: function () {

    12. resolveWith: function ( context, args ) {

    13. state: function () {

    14. then: function ( /* fnDone, fnFail, fnProgress */ ) {

  2. promise: Object

    1. always: function () {

    2. done: function () {

    3. fail: function () {

    4. pipe: function ( /* fnDone, fnFail, fnProgress */ ) {

    5. progress: function () {

    6. promise: function ( obj ) {

    7. state: function () {

    8. then: function ( /* fnDone, fnFail, fnProgress */ ) {

  3. state: "pending"

  4. tuples: Array[3]

构造图

以上只是在初始化构建的时候,我们往下看看动态执行时候的处理

*****************执行期***********************

一个最简单的demo为例子

var d = $.Deferred();    setTimeout(function(){          d.resolve(22)    },0);    d.then(function(val){        console.log(val);   })

当延迟对象被 resolved 时,任何通过 deferred.then或deferred.done 添加的 doneCallbacks,都会被调用。回调函数的执行顺序和它们被添加的顺序是一样的。传递给 deferred.resolve() 的 args 参数,会传给每个回调函数。当延迟对象进入 resolved 状态后,再添加的任何 doneCallbacks,当它们被添加时,就会被立刻执行,并带上传入给 .resolve()的参数

换句话说,我们调用d.resolve(22) 就等于是调用。

匿名函数并传入参数值 22

function(val){        console.log(val); //22   }

当前实际的使用中会有各种复杂的组合情况,但是整的外部调用流程就是这样的

***************** resolve的实现 *******************

我们回顾下,其实Deferred对象,内部的实现还是Callbacks对象,只是在外面再封装了一层API,供接口调用

d.resolve(22)

实际上调用的就是通过这个代码生成的

deferred[ tuple[0] ] = function() {      deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );      return this;  };   deferred[ tuple[0] + "With" ] = list.fireWith;
deferred.resolveWith()

最终执行的就是 list.fireWith

callbacks.fireWith()

所以最终又回到回调对象callbacks中的私有方法fire()了

Callbacks会通过

callbacks.add()

把回调函数给注册到内部的list = []上,我们回来过看看

deferred.then()

d.then(function(val){        console.log(val);   })

***************** then的实现 *******************

then: function( /* fnDone, fnFail, fnProgress */ ) {      var fns = arguments;      return jQuery.Deferred(function( newDefer ) {          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() {                     //省略............              });          });          fns = null;      }).promise();  },
  • 递归jQuery.Deferred

  • 传递了func

  • 链式调用了promise()

因为在异步对象的方法都是嵌套找作用域属性方法的

这里我额外的提及一下作用域

var d = $.Deferred();

这个异步对象d是作用域是如何呢?

第一层:无可争议,浏览器环境下最外层是 window

第二层:jquery本身是一个闭包

第三层: Deferred工厂方法产生的作用域

如果用d.then()方法呢?

很明显then方法又是嵌套在内部的函数,所以执行的时候都默认会包含以上三层作用域+自己本身函数产生的作用域了

我们用个简单图描绘下

根据规则,在最内部的函数能够访问上层作用域的所有的变量

我们先从使用的层面去考虑下结构设计:

demo 1

var defer = $.Deferred();     var filtered = defer.then(function( value ) {          return value * 2;        });     defer.resolve( 5 );     filtered.done(function( value ) {        console.log(value) //10    });

demo 2

var defer = $.Deferred();     defer.then(function(value) {      return value * 2;    }).then(function(value) {      return value * 2;    }).done(function(value) {        alert(value)  //20    });     defer.resolve( 5 );

其实这里就是涉及到defer.then().then().done() 链式调用了

API是这么定义的:

deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

从jQuery 1.8开始, 方法返回一个新的promise(承诺),通过一个函数,可以过滤deferred(延迟)的状态和值。替换现在过时的deferred.pipe()方法。 doneFilter 和 failFilter函数过滤原deferred(延迟)的解决/拒绝的状态和值。 progressFilter 函数过滤器的任何调用到原有的deferred(延迟)的notify 和 notifyWith的方法。 这些过滤器函数可以返回一个新的值传递给的 promise(承诺)的.done() 或 .fail() 回调,或他们可以返回另一个观察的对象(递延,承诺等)传递给它的解决/拒绝的状态和值promise(承诺)的回调。 如果过滤函数是空,或没有指定,promise(承诺)将得到与原来值相同解决(resolved)或拒绝(rejected)。

我们抓住几点:

  • 返回的是新的promise对象

  • 内部有一个滤器函数

从demo 1中我们就能看到

经过x.then()方法处理的代码中返回的this(filtered ),不是原来的$.Deferred()所有产生的那个异步对象(defer )了

所以,每经过一个then那么内部处理的this都要被重新设置,那么为什么要这样处理呢?

源码

then: function( /* fnDone, fnFail, fnProgress */ ) {                      var fns = arguments;                      //分别为deferred的三个callbacklist添加回调函数,根据fn的是否是函数,分为两种情况                      return jQuery.Deferred(function( newDefer ) {                          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 );                                  if ( returned && jQuery.isFunction( returned.promise ) ) {                                      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();                  },

在Deferred传递实参的时候,支持一个flag,jQuery.Deferred(func)

传递一个回调函数

// Call given func if any  if ( func ) {      func.call( deferred, deferred );  }

所以newDefer可以看作是

newDefer = $.Deferred();

那么func回调的处理的就是过滤函数了

deferred[ tuple[1] ](function() {      var returned = fn && 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 === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );      }  });

这里其实也有编译函数的概念,讲未来要执行的代码,预先通过闭包函数也保存起来,使其访问各自的作用域

第一步

分解tuples元素集

jQuery.each( tuples, function( i, tuple ) {     //过滤函数第一步处理  })

第二步

分别为deferred[ done | fail | progress ]执行对应的add方法,增加过滤函数给done | fail | progress 方法

deferred[ tuple[1] ](  传入过滤函数  )//过滤函数 执行的时候在分解

代码即

deferred[done] = list.add = callback.add

第三步

返回return jQuery.Deferred().promise()

此时构建了一个新的Deferred对象,但是返回的的是经过promise()方法处理后的,返回的是一个受限的promise对象

所以整个then方法就处理了2个事情

  • 构建一个新的deferred对象,返回受限的promise对象

  • 给父deferred对象的[ done | fail | progress ]方法都增加一个过滤函数的方法

我们知道defer.then方法返回的是一个新的jQuery.Deferred().promise()对象

那么我们把defer.then返回的称之为子对象,那么如何与父对象var defer = $.Deferred() 关联的起来的

我看看源码

deferred[ tuple[1] ](//过滤函数//)

deferred其实就是根级父对象的引用,所以就嵌套再深,其实都是调用了父对象deferred[ done | fail | progress 执行add罢了

从图中就能很明显的看到 2个不同的deferred对象中 done fail progress分别都保存了不同的处理回调了

deferred.resolve( args )

  • 当延迟对象被 resolved 时,任何通过 deferred.then或deferred.done 添加的 doneCallbacks,都会被调用

  • 回调函数的执行顺序和它们被添加的顺序是一样的

  • 传递给 deferred.resolve() 的 args 参数,会传给每个回调函数

  • 当延迟对象进入 resolved 状态后,再添加的任何 doneCallbacks,当它们被添加时,就会被立刻执行,并带上传入给.resolve()的参数

流程如图

流程解析:

1 执行fire()方法,递归执行list所有包含的处理方法

2 执行了默认的 changeState, disable, lock 方法、

3 执行过滤函数

根据 var returned = fn.apply( this, arguments )的返回值(称作returnReferred)是否是deferred对象

  • 返回值是deferred对象,那么在returnReferred对象的三个回调函数列表中添加newDeferred的resolve(reject,notify)方法,也就是说newDeferrred的执行依赖returnDeferred的状态

  • 不是函数的情况(如值为undefined或者null等),直接链接到newDeferred的resolve(reject,notify) 方法,也就是说 newDeferrred的执行依赖外层的调用者deferred的状态或者说是执行动作(resolve还是reject或者是notify) 此时deferred.then()相当于将自己的callbacklist和newDeferred的callbacklist连接起来

下面就是嵌套deferred对象的划分了

以上就是如何用jQuery 2.0.3源码分析Deferred,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

函数 对象 方法 状态 处理 就是 代码 作用 时候 源码 参数 延迟 三个 流程 顺序 分析 也就是 实际 工厂 情况 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司怎么样 科技赋能下的互联网金融 互联网属科技 远信互联网科技 朗涯互联网科技 华中科技有哪些互联网大佬 科技赋能互联网健康 博兴的互联网电子科技公司 互联网科技中介 顶级互联网科技成果有哪些 宁夏众和广鑫互联网科技有限公司 智腾互联网科技有限公司 开一家科技互联网公司需要多少钱 链环科技传统企业怎么转型互联网 中国互联网十大科技股排名 华夏恒生科技与互联网科技 科技互联网海报 长沙渺峰互联网科技有限公司 互联网科技手抄报图片 深圳互联网科技园地址 深圳互联网络科技有限公司 极限挑战互联网科技 新浪科技互联网 中国的互联网科技企业的崛起 佳云科技和互联网广告 工业互联网等科技实现智能化赋能 无锡工业互联网科技有限公司 领航科技大厦互联网公司 上海万顺科技互联网有限公司招聘 青岛易易互联网科技
0