deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,比如一些Ajax操作,动画操作等。(P.s:紧跟上一节:https://www.cnblogs.com/greatdesert/p/11433365.html的内容)

异步队列有三种状态:待定(pending)、成功(resolved)和失败(rejected),初始时处于pending状态

我们可以使用jQuery.Deferred创建一个异步队列,返回一个对象,该对象含有如下操作:

  • done(fn/arr)                     ;添加成功回调函数,当异步队列处于成功状态时被调用,参数同:jQuery.Callbacks(flags).add(fn/arr)
  • fail(fn/arr)                           ;添加失败回调函数,参数同上
  • progress(fn/arr)                         ;添加消息回调函数,参数同上
  • then(donefn/arr,failfn/arr,profn/arr)     ;同时添加成功回调函数、失败回调函数和消息回调函数
  • always(fn/arr)                       ;添加回调函数到doneList和failList中,即保存两份引用,当异步队列处于成功或失败状态时被调用    ;参数可以是函数、函数列表
  • state()                                  ;返回异步队列的当前状态、返回pending、resolved或者rejected
  • promise(obj)                           ;如果设置了obj参数对象则为obj对象增加异步队列的方法并返回。如果未设置参数obj,则返回当前Deferred对象的只读副本

如果调用$.Diferred()创建一个异步队列,返回后的对象可以调用如下几个方法:

writer by:大沙漠 QQ:22969969

  • resolve(args)                      ;使用指定的参数调用所有的成功回调函数,异步队列进入成功状态,之后就无法再调用
  • reject(args)                           ;使用指定的参数调用所有的失败回调函数,异步队列进入失败状态
  • notify(args)                              ;使用指定的参数调用所有的消息回调函数
  • resolveWith(context,args)               ;使用指定的上下文和参数调用所有的成功回调函数,异步队列进入成功状态
  • rejectWith(context,args)               ;使用指定的上下文和参数调用所有的失败回调函数,异步队列进入失败状态
  • notifyWith(context,args)               ;使用指定的上下文和参数调用所有的消息回调函数

是不是和上一节介绍的Callbacks的fire和fireWith很像,Defferred内部就是通过通过Callback()回调函数列表来实现的,例如:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://libs.baidu.com/jquery/1.7.1/jquery.js"></script>
</head>
<body>
<script>
function f1(x){console.log('f1 '+x);}
function f2(x){console.log('f2 '+x);}
function f3(x){console.log('f3 '+x);} var t = $.Deferred(); //创建异步队列
t.done(f1).fail(f2).progress(f3); //添加成功回调函数、失败回调函数和消息列表回调函数。等同于t.then(f1,f2,f3);
t.notify('test'); //触发所有消息函数列表,输出:f3 test
t.resolve('done'); //触发所有成功回调函数,输出:done
t.reject('fail'); //没有输出,触发成功回调函数后失败回调函数列表就会被禁用,反过来也如此
t.progress(f1); //输出:f1 test。这是因为消息回调函数之前已经被调用过,保存了上下文和参数了,如果之前没有调用,这里就没有输出。
</script>
</body>
</html>

输出如下:

源码分析


异步队列内部的实现原理就是通过jQuery.Callbacks定义三个回调函数列表,分别存储成功、失败、消息回调函数,然后返回一个对象,在该对象上设置done、fail和progress,分别对应这三个回调函数列表的add方法,这样就实现分别添加不同状态的回调函数了

$.Deferred是通过jQuery.extend函数直接挂载到jQuery里的,结构如下:

jQuery.extend({

    Deferred: function( func ) {
var doneList = jQuery.Callbacks( "once memory" ), //成功回调函数列表
failList = jQuery.Callbacks( "once memory" ), //失败回调函数列表
progressList = jQuery.Callbacks( "memory" ), //消息回调函数列表  ;这三个回调函数列表就是存储我们添加的触发函数的
state = "pending", //初始状态:pending
lists = { //后面的方法会遍历变量list中的属性名来为异步队列添加方法deffred.resolve()、resolveWith()、reject()、rejectWith()、notify()和notifyWith()
resolve: doneList,
reject: failList,
notify: progressList
},
promise = { //异步队列的只读副本
/*略*/
},
deferred = promise.promise({}), //异步队列
key; for ( key in lists ) { //添加触发成功、失败、消息回调函数的方法,执行后deferred对象就多了resolve()、resolveWith()、reject()、rejectWith()、notify()和notifyWith()方法。
deferred[ key ] = lists[ key ].fire;
deferred[ key + "With" ] = lists[ key ].fireWith;
} // Handle state
deferred.done( function() { //添加三个成功回调函数,分别用于设置状态为成功(resolved),禁用失败列表函数列表和锁定消息回调函数列表
state = "resolved";
}, failList.disable, progressList.lock ).fail( function() { //添加三个失败回调韩素,分别用于设置状态为失败(rejected),禁用成功列表函数列表和锁定消息回调函数列表
state = "rejected";
}, doneList.disable, progressList.lock ); // Call given func if any
if ( func ) {
func.call( deferred, deferred );
} // All done!
return deferred; //返回异步队列deffrred
},
//...
})

可以看到$.Deferred最后返回的是deferred这个布局变量,而deferred是promise.promise({})的返回值,我们来看看promise的实现方法:

promise = {                        //异步队列的只读副本
done: doneList.add, //添加成功回调函数,引用对应的回调函数列表的callbacks.add(fn/arr)方法,下同
fail: failList.add, //添加失败回调函数
progress: progressList.add, //添加消息回调函数 state: function() { //返回异步队列的当前状态:pending、resolved、rejected之一
return state;
}, // Deprecated
isResolved: doneList.fired,
isRejected: failList.fired, then: function( doneCallbacks, failCallbacks, progressCallbacks ) { //同时添加成功回调函数、失败回调函数和消息回调函数
deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
return this;
},
always: function() { //添加回调函数到doneList和failList中,即保存两份引用,当异步队列处于成功或失败状态时被调用
deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
return this;
},
pipe: function( fnDone, fnFail, fnProgress ) { //过滤当前异步队列的状态和参数,并返回一个新的异步队列的副本,一般用不到
return jQuery.Deferred(function( newDefer ) {
jQuery.each( {
done: [ fnDone, "resolve" ],
fail: [ fnFail, "reject" ],
progress: [ fnProgress, "notify" ]
}, function( handler, data ) {
var fn = data[ 0 ],
action = data[ 1 ],
returned;
if ( jQuery.isFunction( fn ) ) {
deferred[ handler ](function() {
returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
} else {
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
}
});
} else {
deferred[ handler ]( newDefer[ action ] );
}
});
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) { //如果设置了obj参数对象则为obj对象增加异步队列的方法并返回。如果未设置参数obj,则返回当前Deferred对象的只读副本,
if ( obj == null ) { //如果obj为空
obj = promise; //则返回promise对象(是上一层作用域链的promise对象)
} else {
for ( var key in promise ) { //否则遍历promise
obj[ key ] = promise[ key ]; //将promise的所有方法、属性保存到obj中
}
}
return obj; //最后返回obj
}
},

$.Deferred就是对Callbacks回调函数列表的管理而已,产生了一个新的$.Defferred接口,内部添加了一个state表示异步队列的状态。

jQuery源码分析(九) 异步队列模块 Deferred 详解的更多相关文章

  1. jQuery 源码分析(十) 数据缓存模块 data详解

    jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...

  2. jQuery 源码解析(八) 异步队列模块 Callbacks 回调函数详解

    异步队列用于实现异步任务和回调函数的解耦,为ajax模块.队列模块.ready事件提供基础功能,包含三个部分:Query.Callbacks(flags).jQuery.Deferred(funct) ...

  3. jQuery 源码解析(三十) 动画模块 $.animate()详解

    jQuery的动画模块提供了包括隐藏显示动画.渐显渐隐动画.滑入划出动画,同时还支持构造复杂自定义动画,动画模块用到了之前讲解过的很多其它很多模块,例如队列.事件等等, $.animate()的用法如 ...

  4. Vue.js 源码分析(九) 基础篇 生命周期详解

    先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate.created.beforeMount.mounted.beforeupdate.updated   .beforeDes ...

  5. jQuery 源码分析(十六) 事件系统模块 底层方法 详解

    jQuery事件系统并没有将事件监听函数直接绑定到DOM元素上,而是基于数据缓存模块来管理监听函数的,事件模块代码有点多,我把它分为了三个部分:分底层方法.实例方法和便捷方法.ready事件来讲,好理 ...

  6. Python 源码分析:queue 队列模块

    起步 queue 模块提供适用于多线程编程的先进先出(FIFO)数据结构.因为它是线程安全的,所以多个线程很轻松地使用同一个实例. 源码分析 先从初始化的函数来看: 从这初始化函数能得到哪些信息呢?首 ...

  7. jQuery 源码分析(十三) 数据操作模块 DOM属性 详解

    jQuery的属性操作模块总共有4个部分,本篇说一下第2个部分:DOM属性部分,用于修改DOM元素的属性的(属性和特性是不一样的,一般将property翻译为属性,attribute翻译为特性) DO ...

  8. Vue.js 源码分析(十二) 基础篇 组件详解

    组件是可复用的Vue实例,一个组件本质上是一个拥有预定义选项的一个Vue实例,组件和组件之间通过一些属性进行联系. 组件有两种注册方式,分别是全局注册和局部注册,前者通过Vue.component() ...

  9. Vue.js 源码分析(十) 基础篇 ref属性详解

    ref 被用来给元素或子组件注册引用信息.引用信息将会注册在父组件的 $refs 对象上.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素:如果用在子组件上,引用就指向组件实例,例如: ...

随机推荐

  1. 一、Mybatis配置详解

    Mybatis配置详解 XML配置文件层次结构 下图展示了mybatis-config.xml的全部配置元素 properties元素 properties是一个配置属性的元素,让我们能在配置文件的上 ...

  2. Linux常见命令之权限管理命令

    chmod命令 chmod命令用来变更文件或目录的权限.在UNIX系统家族里,文件或目录权限的控制分别以读取.写入.执行3种一般权限来区分,另有3种特殊权限可供运用.用户可以使用chmod指令去变更文 ...

  3. laravel中select2多选,初始化默认选中项

    项目中有发送消息功能,需要能通过搜索,多选用户,来指定发送人.使用 select2 插件来完成. select2 的 html 代码如下: <div class="form-group ...

  4. Mac(PC)连接虚拟机MySQL失败

    解决: 首先登陆虚拟机的MySQL use mysql; select host,user from user; 可以看到,默认的mysql只允许本机访问 将host设置为通配符模式%,Host设置为 ...

  5. 错误InnoDB:Attemptedtoopenapreviouslyopenedtablespace.

    2013-08-04 13:48:22 760 [ERROR] InnoDB: Attempted to open a previously opened tablespace. Previous t ...

  6. WebJar的打包和使用

    前言 WebJar官网:https://www.webjars.org/,对于任何与Servlet 3兼容的容器,WEB-INF/lib目录中的webjar都会自动作为静态资源提供.这是因为WEB-I ...

  7. java基础(14):Eclipse、面向对象、自定义数据类型的使用

    1. Eclipse的应用 1. 常用快捷操作 Ctrl+T:查看所选中类的继承树 例如,在下面代码中,选中Teacher类名,然后按Ctrl+T,就会显示出Teacher类的继承关系 //员工 ab ...

  8. Rpg maker mv角色扮演游戏制作大师简介

    目录 1:简介 2:基本图片展示 3.和js等平台的合作 @(这里写自定义目录标题) 1:简介   <RPG制作大师MV>为<RPG制作大师>的新版本,于18年11月27日登陆 ...

  9. Define the Data Model and Set the Initial Data 定义数据模型并设置初始数据

    This topic describes how to define the business model and the business logic for WinForms and ASP.NE ...

  10. Spring之 JDBC 异常

    JDBC异常抽象 Spring会将数据操作的异常转换为DataAccessException 解析错误码 SQLErrorCodeSQLExceptionTranslator ErrorCode定义 ...