JQuery Deferred 对象剖析
JQuery 中利用 Deferred 对象提供类似 ES2016(aka. es7) 中 Promise 的功能。
JQuery 中的 AJAX 请求函数返回的就是 Deferred 对象。
通过使用 Defered 让异步调用更加可读,实现高级的用法(指定多个回调函数/等待多个 AJAX 请求)。
- JQuery中传统的AJAX请求
$.getJSON('url', data=>{
// 处理返回的JSON数据
console.log(data);
}, err=>{
// 处理出错信息
console.log(err.status);
})
- 使用 Deferred 的AJAX请求
$.getJSON('url').done(data=>{
console.log(data);
}).fail(err=>{
console.log(err.status);
});
这篇文章会着重分析 Deferred/Promise 的状态变化过程,并讲述 Deferred 对象在实际编码中的应用。
创建 Deferred
用户可以使用 Deferred 函数来创建 Deferred 对象
var d1 = $.Deferred();
console.log(d1.state());
Deferred 对象的状态
Deferred 对象有以下三种状态
- pending
- rejected
- resolved
Deferred 对象可以从pending状态转换到rejected状态或者resolved.
这种状态的转换是单向的,也就是说一旦Deferred对象的状态是 rejected/resolved, 对象的状态将不可变。
得到 Deferred 对象的状态
JQuery 提供了三个函数来查看/修改Deferred对象的状态:
deferred.state(), 返回一个字符串表示当前 Deferred 对象的状态deferred.reject(), 将对象的状态设置为 rejecteddeferred.resolve(), 将对象的状态设置为 resolved
下面的代码定义了两个 Deferred 对象,并分别使用 resolve/reject 改变他们的状态
let d1 = $.Deferred();
console.log(d1.state()); // "pending"
d1.resolve();
console.log(d1.state()); // "resolved"
let d2 = $.Deferred();
console.log(d2.state()); // "pending"
d2.reject();
console.log(d2.state()); // "rejected"
Deferred 回调函数
JQuery 提供了方法来指定当 Deferred 对象状态发生变化时的回调函数
指定回调函数
使用 then 方法
then 方法接受两个函数作为参数,当对象的状态变成 resolved, 第一个函数会被调用。
当对象的状态变成 rejected, 第二个函数会被调用。第一个函数接受一个参数,该参数是
defered.resolve函数被调用时传递的第一个参数。
第二个函数接受一个参数,该参数是defered.reject函数被调用时传递的第一个参数。
- 使用 then 和 resolve 方法
var d1 = $.Deferred();
// 注册回调函数
d1.then(function(data){
console.log('First function: ' + data.state);
}, function(err){
console.log('Second function: ' + err);
});
// 做一些耗时的操作
// 改变 deferred 对象状态为 resolved
// 回调函数将被调用,打印信息:First function: successed
d1.resolve({state: 'successed'});
- 使用 then 和 reject 方法
var d2 = $.Deferred();
// 注册回调函数
d2.then(function(data){
console.log('First function: ' + data.state);
}, function(err){
console.log('Second function: ' + err.state);
});
// 改变 deferred 对象状态为 rejected
// 回调函数将被调用,打印信息:Second function: failed
d2.reject({state: 'failed'});
使用 done 方法
使用 done 方法可以指定当 deferred 对象状态变成 resolved 时调用的函数
var deferred = $.Deferred();
deferred.done(function(data){
console.log('Done: ' + data.state);
});
deferred.resolve({state: 'successed'});
使用 fail 方法
使用 fail 方法可以指定当 deferred 对象状态变成 rejected 时调用的函数
var deferred = $.Deferred();
deferred.fail(function(err){
console.log('Fail: ' + err.state);
})
deferred.resolve({state: 'failed'});
使用 always 方法
always 方法接受一个函数作为参数,只要 Deferred 对象的状态发生变化,该函数都会被调用。
链式调用
因为 then/done/fail 函数返回的仍然是类 Deferred 对象,所以我们可以使用他们来指定多个回调函数.
下面这个例子用 done/fail 来指定多个
var deferred = $.Deferred();
deferred.done(data=>{
// Do something
}).done(data=>){
// Do something
}.fail(err=>{
// Handle the error
}).always(()=>{
// Clean the environment
})
Promise 对象
JQuery 还提供了 Promise 对象,可以通过 Deferred 对象的 promise 方法来获取该对象的 Promise 对象。=
Promise 对象有以下特点:
- Promise 对象没有
reject/resolve方法 - Promise 对象的状态跟 Deferred 对象保持一致
- Promise 对象通过
state()方法获取跟它绑定的 Deferred 的状态 - Proimse 对象也可以使用
then/done/fail方法来指定回调函数 - Promise 可以调用 promise 方法获取它自身
var deferred = $.Deferred();
var promise = deferred.promise();
deferred.reject();
console.log(deferred.state()); // rejected
console.log(promise.state()); // rejected
console.log(promise.promise() === promise); // true, Promise 对象的 promis() 方法返回的是它自己
then 和 done/fail 的差异
done/fail 返回的是 Deferred 对象自身
then 方法返回的是一个新的 Promise 对象
使用 done/fail 方法返回 Deferred 对象
var d1 = $.Deferred();
var d2 = d1.done();
var d3 = d1.fail();
console.log(d1 === d2); // true
console.log(d1 === d3); // true
使用 then 方法返回 Promise 对象
使用 then 方法我们需要明白的几个关键点是:
方法返回的是 Promise 对象,该对象没有 resolve/reject 方法。
Deferred 对象的
then方法, 会创建一个新的 Deferred 对象,并返回新 Deferred 对象的 Promise 对象。
而且then方法返回的对象 跟 Deferred 对象的 Promise 对象不相等, 多次调用 then 对象会产生多个 Deferred 对象。
下面的例子对比了多次调用 then 方法产生的 Promise 对象
var d1 = $.Deferred();
var p2 = d1.then(); // 调用 then 方法返回一个 Promise 对象
var p3 = d1.then(); // 调用 then 方法返回一个新的 Promise 对象
console.log('reject' in d1); // false, 查看 then 方法返回的对象中是否有 reject 方法
console.log('reject' in p2); // false, 查看 then 方法返回的对象中是否有 reject 方法
console.log(p2 === d1); // false, 检查 d1 是否与 p2 相等
console.log(p2 === d1.promise()); // false, 查看 d1 的 promise 是否与 p2 相等
console.log(p2 === p3); // false, p2 和 p3 的值不同
Deferred 对象的状态发生改变后,then 方法产生的 Promise 对象的状态不会立即发生变化
Deferred 对象状态发生变化后, 等待一段时间后 then 方法产生的 Promise 对象的状态才会发生相应的变化
var deferred = $.Deferred();
var new_promise = deferred.then();
deferred.reject('reject')
console.log(`d1 state: ${deferred.state()}`); // rejected
console.log(`new_promise state: ${new_promise.state()}`); // pending
setTimeout(`console.log("new_promise state after 100 miliseconds: ${new_promise.state()}")`, 100); // 100 毫秒后, new_promise 的状态变成了 rejected
发生了什么
Deferred 对象的状态发生改变后,then 方法产生的 Promise 对象的状态并没有立即发生变化, 而是等待了一段时间后才改变。
这段时间内,发生了什么那?
我们以调用 Deferred 对象的 resolve 方法作为例子来说明。 调用 reject 方法的情况与此类似。
- 首先假设我们构造了Deferred 对象 d1
- 然后调用 then 方法,并且传入两个函数作为参数 fun1, fun2:
var p2 = d1.then(fun1, fun2) - 调用
d1.resolve(data)方法将 d1 的状态设置为 resolved, 此时d1 的状态是 resolved, p2 的状态是 pending - fun1 会被调用, 参数为
d1.resolve方法的参数:var new_data = fun1(data) - 假设 p2 对应的 Deferred 对象是 d2.
- d2 的 resolve 方法会被调用, 参数为 fun1 的返回值:
d2.resolve(new_data) - p2 的状态变为 resolved
- p2 的回调函数会被调用
下面的代码展示了 then 方法产生的 Promise 对象的状态变化。以及如何给回调函数传递参数
var d1 = $.Deferred();
function fun1(data){
console.log(`p2 state in fun1: ${p2.state()}`);
console.log(`data in fun1: ${data}`);
return data * 3;
}
function fun2(error){
return 'new data from fun2';
}
var p2 = d1.then(fun1, fun2);
p2.done(data=>{
console.log(`p2 state in done: ${p2.state()}`);
console.log(`data in done: ${data}`);
});
d1.resolve(10);
/* 屏幕输出为
p2 state in fun1: pending
data in fun1: 10
p2 state in done: resolved
data in done: 30
*/
在网页中使用 Deferred
自定义函数
明白了 Deferred 的原理,我们就可以使用 Deferred.
下面一段代码定义了一个函数, 在函数中定义了一些耗时的操作。
函数返回 Promise 对象, 可以使用 done/fail/then 注册回调函数
function say_hello(){
// 创建 Deferred 对象
var deferred = $.Deferred();
// 做一些耗时的操作,操作完成后调用 resolve 或者 reject 函数结束。
// 我们用 setTimeout 函数模拟一段耗时操作:
// 等待五秒钟后,调用 Deferred 的 resolve 方法来改变状态
setTimeout(deferred.resolve.bind(deferred, 'hello world'), 5000);
// 也可以使用 AJAX 操作
/*
$.getJSON('/api/names').done(data=>{
if(data.state == 'successed'){
deferred.resolve(data);
}else{
deferred.reject(data);
}
});
*/
return deferred.promise(); // 返回 promise 对象, 防止外界对 Deferred 对象的状态进行改变
}
// 调用 say_hello函数,并使用 done/fail/then 方法注册回调函数
say_hello().done(msg=>{
console.log(msg);
});
$.when
跟 ES2016 中 Prmomise.all 函数类似。
JQuery 提供了 when 函数, 它可以接受多个 Deferred/Promise 对象作为参数。并返回一个 Promise 对象。
新的 Promise 对象会等待参数中所有的对象状态变为 resolved/reject。
如果参数中任何一个对象的状态变为 rejected, 那么 Promise 对象的状态变为 rejected。 否则变为 resolved。
// 创建一个函数,如果参数大于500, 则将内置的 Deferred 对象状态变为 resolved
// 如果参数小于500, 则将内置的 Deferred 对象状态变为 rejected
function get_promise(delay){
// 创建 Deferred 对象
var deferred = $.Deferred();
if(delay > 500){
setTimeout(deferred.resolve.bind(deferred, delay/100), delay);
}else{
setTimeout(deferred.reject.bind(deferred, delay/100), delay);
}
return deferred.promise(); // 返回 promise 对象
}
// 如果任一参数状态转变为 rejected, when 函数产生的 promise 对象状态会理解变为 rejected。
// 并将第一个 Deferred 对象的错误信息传递给回调函数
$.when(get_promise(800), get_promise(100), get_promise(300)).fail(error=>{
console.log(error); // 1
});
// 否则 when 函数会等待所有的 Deferred 对象状态变为 resolved, 并将所有 Deferred 对象的返回值依次传递给回调函数
$.when(get_promise(900), get_promise(600), get_promise(1000)).done((d1, d2, d3)=>{
console.log(d1); // 9
console.log(d2); // 6
console.log(d3); // 10
});
$.when(get_promise(800), get_promise(900), get_promise(1000)).done((...datas)=>{
console.log(datas); // [8, 9, 10]
});
转载请注明出处: http://www.cnblogs.com/zf-l/p/jq_deferred.html
JQuery Deferred 对象剖析的更多相关文章
- javascript --- jQuery --- Deferred对象
javascript --- jQuery --- Deferred对象 javascript的函数式编程是多么引人入胜,jQuery使代码尽可能的精简,intelligent! defer - 必应 ...
- jQuery.Deferred对象
一.前言 jQuery1.5之前,如果需要多次Ajax操作,我们一般会使用下面的两种方式: 1).串行调用Ajax $.ajax({ success: function() { $.ajax({ su ...
- JQuery Deferred 对象
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html <jQu ...
- 使用JQuery Deferred对象的then() 解决多个AJAX操作顺序依赖的问题
原文地址:http://www.2cto.com/kf/201507/424202.html 之前的文章javascript异步代码的回调地狱中提到了编写AJAX代码经常遇到的3个问题,现在我们看下如 ...
- jQuery Deferred对象详细源码分析(-)
本系列文章讲介绍这个Deferred东西到底拿来干什么,从1.5版本加进来,jQuery的很多代码都重写了.直接先上源码分析了,清楚了源码分析,下节将讲具体的应用 以及应用场景. 创建对象 var d ...
- JQuery Deferred对象使用小结
场景描述 如下,打开页面时,获取默认选中的项目,同时也会初始化Combobox下拉框下拉列表数据 问题描述 获取默认选中项目及下拉列表的js函数位于common.js文件,类似如下: // 根据项目类 ...
- 利用 Jquery Deferred 异步你的程序
最近在做公司QA系统改造时,有这样的一个场景. QA系统中有些数据项需要从JIRA平台(一个国外项目与事务跟踪工具)中获取,JIRA平台提供了很完善的Rest API. 现在的要求是,在QA系统中提交 ...
- JS魔法堂:jQuery.Deferred(jQuery1.5-2.1)源码剖析
一.前言 jQuery.Deferred作为1.5的新特性出现在jQuery上,而jQuery.ajax函数也做了相应的调整.因此我们能如下的使用xhr请求调用,并实现事件处理函数晚绑定. var p ...
- jQuery.Deferred(jQuery1.5-2.1)源码剖析
jQuery.Deferred作为1.5的新特性出现在jQuery上,而jQuery.ajax函数也做了相应的调整.因此我们能如下的使用xhr请求调用,并实现事件处理函数晚绑定. var promis ...
随机推荐
- 我的第一个python web开发框架(2)——一个简单的小外包
第一部分说明 第一部分大概有20来章,主要讲的是一些开发常识.开发前中后期准备内容.开发环境与服务器部署环境安装设置.python基础框架结构与功能等内容,代码会比较简单. 本系列会以故事的方式,向大 ...
- ionic2+Angular2:套接口明细步骤,以登录功能为例
1.在app.module.ts引用HttpModul,并在imports内引用.截图如下: 2.在src目录下新建http服务.命令行:ionic g provider HttpService ...
- HDU-2222文字检索
题目: In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiske ...
- golang 标准库间依赖的可视化展示
简介 国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内 ...
- 如何用Django从零开始搭建一个网站(0)
python,django等安装就直接略过了.下面直接奔如主题,搭建网站. Step1:新建一个django project,运行命令:‘django-admin startproject myPit ...
- iOS在类内部怎么访问实例变量比较好?
OC在类文件的内部访问实例变量,有直接访问和使用getter/setter方法访问两种方式,它们的区别有: 1.直接访问不经过OC的方法分发(method dispatch),所以访问速度比较快,在这 ...
- scala中的Type使用
trait Base { val name: String } case class S( name: String, age: Int ) extends Base case class F( na ...
- cocos2dx - v2.3.3编辑器骨骼动画
接上一节内容:cocos2dx - v2.3.3编辑器简单使用及不同分辨率适配 本节主要Cocos骨骼动画的创建及使用 一.新建 用Cocos Studio工具新建一个状态栏项目.如下图: 当然也可以 ...
- 【学习】苹果iPhone safari浏览器样式重置修复按钮圆角bug
iPhone safari浏览器中,input按钮会按苹果的默认UI来渲染,例如,写的按钮明明是这个样的: 但是实际就会是这个样子: 怎么办呢? 为按钮添加:-webkit-appearance: n ...
- Javascript之pixi框架学习
pixi 创建渲染器(renderer) 创建一个可以播放动画的区域,相当于(canvas). var renderer = PIXI.autoDetectRenderer(512, 512); do ...