jquery.Deferred promise 解决异步回调

本贴最后更新于 2989 天前,其中的信息可能已经时移世改

感觉Jquery的Deferred 对象很有用并且掌握难度也有,花点时间还是值得研究下的。

注:博文转至 http://www.cnblogs.com/greatluoluo/p/5721746.html  作者张三的美丽家园



我们先来看一下编写AJAX编码经常遇到的几个问题:

1.由于AJAX是异步的,所有依赖AJAX返回结果的代码必需写在AJAX回调函数中。这就不可避免地形成了嵌套,ajax等异步操作越多,嵌套层次就会越深,代码可读性就会越差。

$.ajax({
url: url,
data: dataObject,
success: function(){
console.log("I depend on ajax result.");
},
error: function(){}
});

console.log("I will print before ajax finished.");
2.如果AJAX请求之间存在依赖关系,我们的代码就会形成Pyramid of Doom(金字塔厄运)。比如我们要完成这样一件事:有4个供Ajax访问的url地址,需要先Ajax访问第1个,在第1个访问完成后,用拿到的返回数据作为参数再访问第2个,第2个访问完成后再第3个...以此到4个全部访问完成。按照这样的写法,似乎会变成这样:

$.ajax({
url: url1,
success: function(data){
$.ajax({
url: url2,
data: data,
success: function(data){
$.ajax({
//...
});
}
});
}
});

3.考虑这种场景,假如我们同时发送两个Ajax请求,然后要在两个请求都成功返回后再做一件接下来的事,想一想如果只按前面的方式在各自的调用位置去附加回调,这是不是很困难?

可以看到:JavaScript中类似于AJAX这种异步的操作,会导致代码嵌套层次复杂,可读性差,有的时候甚至是实现需求都非常困难。为了解决这种异步回调难的问题,CommonJS组织制定了异步模式编程规范Promises/A。目前该规范已经有了很多的实现者,比如Q, when.js, jQuery.Deffered()等。我们以jQuery.Deffered学习下Promise。

Promise的状态

Promise对象有3种可能的状态:肯定状态(resolved)、否定状态(rejected)、等待状态(pending)。刚开始创建的Promise对象处于pending状态,只能从pending变成resolved或者是从pending变成rejected状态。

var df1 = $.Deferred();
console.log(df1.state());//pending

var df2 = $.Deferred();
df2.resolve();//resolved
console.log(df2.state());

var df3 = $.Deferred();
df3.reject();
console.log(df3.state());//rejected


$.Deferred()创建一个延迟对象(也就是Promise对象),deferred.state()可以获取Promise对象当前所处的状态。deferred.resolve()和deferred.reject()则是用来改变Promise对象的状态。

Promise添加回调函数

Promise对象有3种状态,我们可以分别为这3种状态注册回调函数。当Promise处于某个状态的时候,会触发这个状态下注册的回调函数。

var df = $.Deferred();
df.done(function(){alert("success");});
df.fail(function(){alert("fail");});
df.progress(function(){alert("progress");});

df.notify();

df.resolve();
// df.reject();


done()、fail()、progress()分别注册resolved、rejected、pending状态下的回调函数。通过resolve()、reject()、notify()可以触发事先注册的回调函数。

Promise是支持链式调用的,上面的代码可以写成下面的样子。

var df = $.Deferred();
df.done(function(){alert("success");})
.fail(function(){alert("fail");})
.progress(function(){alert("progress");});
Promise支持多个回调函数,会按照注册顺序调用。
var df = $.Deferred();
df.done(function(){alert("first");})
.fail(function(){alert("fail");});

df.done(function(){alert("second");});
df.done(function(){alert("third");});

df.resolve();


deferred.always()添加的回调函数,无论Promise是resolved状态还是rejected状态,都会被调用。

var df1 = $.Deferred();
df1.always(function(type){alert(type);});
df1.resolve("resolve");

var df2 = $.Deferred();
df2.always(function(type){alert(type);});
df2.reject("reject");


progress()和notify()能够用来实现进度条效果,因为notify()允许调用多次,而reject()和resolve()只能调用一次。这个很好理解,因为一旦状态变成resolved或者是rejected,就不能再改变其状态,也没有必要。

var df = $.Deferred();
df.done(function(){alert("success");});
df.fail(function(){alert("fail");});
df.progress(function(){alert("progress");});

// resolve()调用 2 次,但是只能触发 1 次 success
df.resolve();
df.resolve();

var mudf = $.Deferred();
mudf.done(function(){alert("success");});
mudf.fail(function(){alert("fail");});
mudf.progress(function(){alert("progress");});


// 每次调用notify都会触发progress回调函数

mudf.notify("%10");
mudf.notify("%20");

rejectWith()、resolveWith()、notifyWith()功能上和reject()、resolve()、notify()没有什么差别,主要差别在于回调函数中的执行上下文(方法中的this)和参数形式。具体差别可以参考"JQuery.Callbacks系列一:api使用
// 老的ajax写法

$.ajax({
url: "test.html",
success: function(){
alert("success");
},
error:function(){
alert("error");
}
});

// 使用promise后的写法

$.ajax("test.html")
.done(function(){})
.fail(function(){})
.done(function(){)
.fail(function(){);

 

JQuery中的Deferred对象与Promise对象区别

JQuery.Deferred相关的API,有的返回的是Deferred对象,有的返回的是Promise对象。如done()、reject()等大部分函数返回的都是Deferred对象,$.when()和then()函数返回的是Promise对象。具体可以参考JQuery API文档。

JQuery官方对Promise Objects的解释是:

This object provides a subset of the methods of the Deferred object (then, done, fail, always, progress, state and promise) to prevent users from changing the state of the Deferred.

可以看到Promise对象其实就是Deferred对象的一部分,Deferred对象提供了notify、reject、resolve等改变状态的方法,但是Promise对象没有提供这些方法。

文章开始提到的AJAX问题1~3,问题1可以很容易通过Promise得到解决。问题2和问题3是通过$.when()和deferred.then()得到解决,由于这2个API相对来说复杂一些,以后的文章再分析这2个API。

详解"这篇文章中的fire()和fireWith()。

上面简单的介绍了Promise的使用方式,我们可以用Promise的方式来编写AJAX代码。可以很容易地看出:使用Promise后代码嵌套层次少了,代码是纵向增长的,而不再是横向增长。而且使用Promise,可以指定多个ajax回调函数。

jquery Deferred 快速解决异步回调的问题

function ok(name){

var dfd = new $.Deferred();
callback:func(){

return dfd.resolve( response );
}

return dfd.promise();
}

$.when(ok(1),ok(2)).then(function(resp1,resp2){})


//相关API 分成3类

1类:$.when(pro1,pro1) 将多个 promise 对象以and的关系 合并为1个

2类:promise 激发为 解决 deferred.resolve([ args ] ) deferred.resolveWith( context, [ args ] )

和 拒绝 .reject .rejectWith

context 上下文 替换 this 和通知 .notify .notifyWith

3类: 对激发的响应 解决时deferred.done(args) 拒绝时 deferred.fail() 通知时 deferred.progress()

不管 解决 或 拒绝 deferred.always()

deferred.then( doneCallbacks, failCallbacks [, progressCallbacks] )

promise(或者叫deferred 延迟对象如何获取?)

var dfd = new $.Deferred(); return dfd.promise();

返回promise当前状态

deferred.state() pending(尚未完成) resolved rejected

 

管道

deferred.pipe( [ doneFilter ], [ failFilter ] )

var defer = $.Deferred()

var filtered = defer.pipe( null, function( value ) {

return value * 3;
});

defer.reject( 6 );
filtered.fail(function( value ) {
alert( "Value is ( 3*6 = ) 18: " + value );
});




  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 731 关注
  • Deferred
    1 引用 • 1 回帖
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    729 引用 • 1278 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    90 引用 • 59 回帖 • 5 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 644 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 175 关注
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    951 引用 • 943 回帖
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    36 引用 • 155 回帖
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 116 关注
  • RemNote
    2 引用 • 16 回帖 • 9 关注
  • Latke

    Latke 是一款以 JSON 为主的 Java Web 框架。

    71 引用 • 535 回帖 • 820 关注
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 214 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    167 引用 • 595 回帖 • 1 关注
  • sts
    2 引用 • 2 回帖 • 226 关注
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 206 关注
  • Visio
    1 引用 • 2 回帖
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 1 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 391 关注
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 157 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 260 关注
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 99 关注
  • danl
    164 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 31 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 20 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    132 引用 • 796 回帖 • 1 关注
  • Word
    13 引用 • 40 回帖