jquery.Deferred promise 解决异步回调

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

感觉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 回帖 • 745 关注
  • Deferred
    1 引用 • 1 回帖
  • JavaScript

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

    710 引用 • 1173 回帖 • 176 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    51 引用 • 37 回帖
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 693 关注
  • 分享

    有什么新发现就分享给大家吧!

    242 引用 • 1746 回帖 • 1 关注
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    15 引用 • 7 回帖 • 7 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    131 引用 • 1114 回帖 • 150 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    131 引用 • 3639 回帖
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖 • 1 关注
  • V2Ray
    1 引用 • 15 回帖
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    91 引用 • 751 回帖
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 383 回帖 • 2 关注
  • 电影

    这是一个不能说的秘密。

    120 引用 • 597 回帖 • 2 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    51 引用 • 190 回帖
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    324 引用 • 1395 回帖 • 2 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 602 关注
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • 倾城之链
    23 引用 • 66 回帖 • 96 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    148 引用 • 257 回帖 • 1 关注
  • 笔记

    好记性不如烂笔头。

    303 引用 • 777 回帖
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 597 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 21 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    108 引用 • 54 回帖 • 1 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 25 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 54 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    1 引用 • 11 回帖
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    14 引用 • 7 回帖 • 1 关注