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. RPA中房产证的 OCR 识别

    客户需求,识别一些证件内容,包括身份证.户口本.营业执照.银行卡以及房产证,前四个比较容易实现,不管是艺赛旗的 RPA 还是百度的 OCR 都有接口,直接调用即可,但是都没有房产证的 OCR 识别,只 ...

  2. 借助Git实现本地与GitHub远程双向传输(同步GitHub仓库)以及一些使用错误解决

    前言 GitHub作为程序员必备的学习交流平台,虽然在国内速度不算快,但只要好好利用这个平台,我相信还是可以学习到很多东西.在暑期的时候,我曾经就初次远程连接到了GitHub,但开学后,不知道为什么又 ...

  3. Docker学习——基本使用

    最近公司项目要用docker部署,第一次接触,记录一下,方便使用时查阅. 你有没有遇到过这种情况,在本地运行良好的代码,在另一台电脑或者另一个环境里一堆bug,可以说是水土不服,本质上是两个电脑的运行 ...

  4. WPF 使用动画设置特殊值的方法

    例如设置Visibility属性时: 第一种方式: <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIEleme ...

  5. vue拖拽组件开发

    vue拖拽组件开发 创建临时vue项目 先查看node和npm版本,怎么安装就不多多bb了 再安装vue-cli npm install vue-cli -g //全局安装 vue-cli 检测是否安 ...

  6. HikariCP监控指标介绍和应用

    概述 HikariCP提供了一些监控指标,他的监控指标都是基于MicroMeter提供出来的,然后支持Prometheus和Dropwizard.本次我们将讨论一下HikariCp的监控指标有哪些,为 ...

  7. dictionary vs Hashtables

    DictionaryDictionary is generic type Dictionary<TKey,TValue>Dictionary class is a strong type ...

  8. Qt Creator配置MSVC调试器

    安装完QT后会看到Qt Creator中的MSVC构建组件带有黄色的感叹号,那是因为没有调试器的原因.由于Qt-MSVC版本套件没有默认安装调试器, 需要我们自己手动下载安装. 根据官方文档http: ...

  9. [b0001] 伪分布式 hadoop 2.6.4

    说明: 任务:搭建Hadoop伪分布式版本. 目的:快速搭建一个学习环境,跳过这一环境,快速进入状态,使用Hadoop一些组件做些任务 没有选择2.7,觉得bug比较多,不稳定. 选择伪分布式简单快速 ...

  10. k8s资产清单(二)

    什么是清单 说白了清单是k8s当中用来定义pod的文件,语法格式遵循yaml语法,在yaml当中可以定义控制器类型,元数据,容器端口号等等等....,也可以针对于清单对pod进行删除等操作 为什么太学 ...