读jQuery之二十(Deferred对象)--(转)
原博文地址:http://www.cnblogs.com/snandy/archive/2012/12/19/2812935.html
Deferred对象是由.Deferred构造的,.Deferred被实现为简单工厂模式。
它用来解决JS中的异步编程,它遵循 Common Promise/A 规范。实现此规范的还有 when.js 和 dojo。
$.Deferred作为新特性首次出现在版本1.5中,这个版本利用Deferred又完全重写了Ajax模块。
$.Deferred在jQuery代码自身四处被使用,分别是promise方法、DOM ready、Ajax模块、动画模块。
这里以版本1.8.3分析,由于1.7后$.Callbacks从Deferred中抽离出去了,目前版本的deferred.js代码不过150行,而真正$.Deferred的实现只有100行左右。
jQuery.extend({
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") ]
],
...
// All done!
return deferred;
},
// Deferred helper
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
....
return deferred.promise();
}
});
$.Deferred的实现
- 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态
- 创建了一个promise对象,具有state、always、then、primise方法
- 通过扩展primise对象生成最终的Deferred对象,返回该对象
$.when的实现
- 接受若干个对象,参数仅一个且非Deferred对象将立即执行回调函数
- Deferred对象和非Deferred对象混杂时,对于非Deferred对象remaining减1
- Deferred对象总数 = 内部构建的Deferred对象 + 所传参数中包含的Deferred对象
- 所传参数中所有Deferred对象每当resolve时remaining减1,直到为0时(所有都resolve)执行回调
这就是.Deferred和.when的全部了,各个方法及使用稍后介绍。
代码阅读中会发现then和when方法的实现最难理解,看多次,后感回味无穷,非常巧妙。then内部会用到不同寻常的递归,when用到了计数,每次异步成功后减一,直到为0后表示全部异步操作成功,这时才可执行回调。
上面提到Deferred里有3个$.Callbacks的实例,Deferred自身则围绕这三个对象进行更高层次的抽象。以下是Deferred对象的核心方法
- done/fail/progress 是 callbacks.add,将回调函数存入
- resolve/reject/notify 是 callbacks.fire,执行回调函数(或队列)
下面举一些示例看看如何使用Deferred对象。
一、done/resolve
function cb() {
alert('success')
}
var deferred = $.Deferred()
deferred.done(cb)
setTimeout(function() {
deferred.resolve()
}, 3000)
在HTTP中表示后台返回成功状态(如200)时使用,即请求成功后可执行成功回调函数。
二、fail/reject
function cb() {
alert('fail')
}
var deferred = $.Deferred()
deferred.fail(cb)
setTimeout(function() {
deferred.reject()
}, 3000)
在HTTP中表示后台返回非成功状态时使用,即请求失败后可执行失败回调函数。
三、progress/notify
function cb() {
alert('progress')
}
var deferred = $.Deferred()
deferred.progress(cb)
setInterval(function() {
deferred.notify()
}, 2000)
在HTTP中表示请求过程中使用,即请求过程中不断执行回调函数。这可用在文件上传时的loading百分比或进度条。
四、链式操作
function fn1() {
alert('success')
}
function fn2() {
alert('fail')
}
function fn3() {
alert('progress')
}
var deferred = $.Deferred()
deferred.done(fn1).fail(fn2).progress(fn3) // 链式操作
setTimeout(function() {
deferred.resolve()
//deferred.reject()
//deferred.notify()
}, 3000)
这样可以很方便了添加成功,失败,进度回调函数。
五,便利函数then,一次添加成功,失败,进度回调函数
function fn1() {
alert('success')
}
function fn2() {
alert('fail')
}
function fn3() {
alert('progress')
}
var deferred = $.Deferred()
deferred.then(fn1, fn2, fn3)
调用then后还可以继续链式调用then添加多个不同回调函数,这个then也正是jQuery对 Common Promise/A 的实现。
六、使用always方法为成功,失败状态添加同一个回调函数
var deferred = $.Deferred()
deferred.always(function() {
var state = deferred.state()
if ( state === 'resolved') {
alert('success')
} else if (state === 'rejected') {
alert('fail')
}
})
setTimeout(function() {
deferred.resolve()
//deferred.reject()
}, 3000)
回调函数中可以使用deferred.state方法获取异步过程中的最终状态,这里我调用的是deferred.resolve,因此最后的状态是resolved,表示成功。
七、when方法保证多个异步操作全部成功后才回调
function fn1() {
alert('done1')
}
function fn2() {
alert('done2')
}
function fn3() {
alert('all done')
}
var deferred1 = $.Deferred()
var deferred2 = $.Deferred()
deferred1.done(fn1)
deferred2.done(fn2)
$.when(deferred1, deferred2).done(fn3)
setTimeout(function() {
deferred1.resolve()
deferred2.resolve()
}, 3000)
先后弹出了done1、done2、all done。 如果setTimeout中有一个reject了,fn3将不会被执行。
八、deferred.promise()方法返回只能添加回调的对象,这个对象与$.Deferred()返回的对象不同,只能done/fail/progress,不能resolve/reject/notify。即只能调用callbacks.add,没有callbacks.fire。它是正统Deferred对象的阉割版。
有了Deferred,我们使用jQuery书写ajax的风格可以这样了
$.ajax(url)
.done(success)
.fail(fail)
看似和以前比较也没什么优点,但它还可以添加多个回调
$.ajax(url)
.done(success1)
.done(success2)
.fail(fail2)
.fail(fail2)
1.5之前的则不行
如果多个请求完成后才算成功,1.5之前的是无法解决的,现在则可以用$.when搞定
var ajax1 = $.ajax(url1)
var ajax2 = $.ajax(url2)
$.when(ajax1, ajax2).done(success)
如果项目中有一些异步问题不妨用用Derferred。
相关:
http://www.infoq.com/cn/news/2011/09/js-promise
http://www.erichynds.com/jquery/using-deferreds-in-jquery/
http://sitr.us/2012/07/31/promise-pipelines-in-javascript.html
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
原博文地址:http://www.cnblogs.com/snandy/archive/2012/12/19/2812935.html
读jQuery之二十(Deferred对象)--(转)的更多相关文章
- 读jQuery之二十(Deferred对象)
Deferred对象是由$.Deferred构造的,$.Deferred被实现为简单工厂模式. 它用来解决JS中的异步编程,它遵循 Common Promise/A 规范.实现此规范的还有 when. ...
- deferred对象和promise对象(二)---deferred对象
早上醒来,继续讨论deferred对象和primise对象. deferred对象的的方法: 1.$.Deferred()-----生成一个deferred对象 2.deferred.done()-- ...
- jQuery入门二(DOM对象与jQuery对象互相转换)
- DOM对象与jQuery对象互相转换 第一篇说过,DOM对象不能调用jQuery对象的属性和方法,同样jQuery对象也不能调用DOM对象的属性和方法.但是在实际开发中,可能两者间需要互相调用对方 ...
- jQuery的deferred对象详解(二)
Deferred对象是由$.Deferred构造的,$.Deferred被实现为简单的工厂模式. $.Deferred的实现 创建三个$.Callbacks对象,分别表示成功done,失败fail,处 ...
- 亲自打造Deferred对象
经过对比之后,决心学习jQuery,自己打造一个Deferred对象.var util = require('./util.js');function Callbacks() { var list = ...
- jQuery中deferred对象的使用(二)
接上一回的内容,漏了一个always()方法,参数也是回调函数,与done和fail不同的是,无论任何情况都执行always方法中的回调. deferred对象的使用(二) deferred对象不光可 ...
- 读jQuery源码 - Deferred
Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...
- 【转载】学习资料存档:jQuery的deferred对象详解
我在以前的文章里提到promise和deferred,这两个东西其实是对回调函数的一种写法,javascript的难点之一是回调函数,但是我们要写出优秀的javascript代码又不得不灵活运用回调函 ...
- jQuery的deferred对象详解(一)
最近一段时间,都在研究jquery里面的$.Deffered对象,几天都搞不明白,其中源码的运行机制,网上查找了相关的资料,<jQuery的deferred对象详解>阮一峰老师的文章,里面 ...
随机推荐
- html/css/javascript练习代码
这两天心血来潮学习了前端,自己也做了个小小的网页,不好看QAQ 不过网页上集结了很多零碎的知识,在这里先马克一下.图片地址:https://github.com/lesroad/html-css-js ...
- .NET中使用Redis:http://www.cnblogs.com/yangecnu/p/Introduct-Redis-in-DotNET.html
.NET中使用Redis Redis是一个用的比较广泛的Key/Value的内存数据库,新浪微博.Github.StackOverflow 等大型应用中都用其作为缓存,Redis的官网为http: ...
- node 封装db层
var db = {}; var mysql = require('mysql'); var pool = mysql.createPool({ connectionLimit: , host: '1 ...
- Django知识点总结
一.什么是web框架? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. web应 ...
- 第9课:备份mysql数据库、重写父类、unittest框架、多线程
1. 写代码备份mysql数据库: 1)Linux下,备份mysql数据库,在shell下执行命令:mysqldump -uroot -p123456 -A >db_bak.sql即可 impo ...
- python项目中requirements的巧用(一键导入所有安装包)
一个Python 项目中可能安装很多安装包, 再次创建虚拟环境是需要重新安装的话很麻烦也费时间, 或者项目部署的时候避免重装, 可以将现有项目的所有安装包记录在requirements.txt 文件, ...
- (四) ffmpeg filter学习-filter命令学习
http://blog.csdn.net/joee33/article/details/51946712 http://blog.csdn.net/tkp2014/article/details/53 ...
- pom配置之:snapshot快照库和release发布库
在使用maven过程中,我们在开发阶段经常性的会有很多公共库处于不稳定状态,随时需要修改并发布,可能一天就要发布一次,遇到bug时,甚至一天要发布N次.我们知道,maven的依赖管理是基于版本管理的, ...
- 密钥库文件格式[keystore]代码
密钥库文件格式[keystore]代码 格式 : JKS 扩展名 : .jks/.ks 描述 : [Java Keystore]密钥库的Java实现版本,pro ...
- Objective-C-----协议protocol,代码块block,分类category
概述 ObjC的语法主要基于smalltalk进行设计的,除了提供常规的面向对象特性外,还增加了很多其他特性,本文将重点介绍objective-C中一些常用的语法特性. 当然这些内容虽然和其他高级语言 ...