javascript异步代码的回调地狱以及JQuery.deferred提供的promise解决方式
我们先来看一下编写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使用具体解释"这篇文章中的fire()和fireWith()。
上面简单的介绍了Promise的使用方式。我们能够用Promise的方式来编写AJAX代码。能够非常easy地看出:使用Promise后代码嵌套层次少了,代码是纵向增长的,而不再是横向增长。并且使用Promise。能够指定多个ajax回调函数。
// 老的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能够非常easy通过Promise得到解决。问题2和问题3是通过$.when()和deferred.then()得到解决。因为这2个API相对来说复杂一些,以后的文章再分析这2个API。
參考文章
"异步JavaScript与Promise"作者ACGTOFE
javascript异步代码的回调地狱以及JQuery.deferred提供的promise解决方式的更多相关文章
- JavaScript异步编程__“回调地狱”的一些解决方案
异步编程在JavaScript中非常重要.过多的异步编程也带了回调嵌套的问题,本文会提供一些解决“回调地狱”的方法. setTimeout(function () { console.log('延时触 ...
- 使用JQuery Deferred对象的then() 解决多个AJAX操作顺序依赖的问题
原文地址:http://www.2cto.com/kf/201507/424202.html 之前的文章javascript异步代码的回调地狱中提到了编写AJAX代码经常遇到的3个问题,现在我们看下如 ...
- js中的回调函数 和promise解决异步操作中的回调地狱问题。
回调函数 : 函数作为参数传递到另外一个函数中.简单数据类型和引入数据类型中的数组和对象作为参数传递大家肯定都不陌生,其实引用数据类型中的函数也是可以的. 事实上大家见到的很多,用到的也很多,比如jQ ...
- Javascript事件模型系列(三)jQuery中的事件监听方式及异同点
作为全球最知名的js框架之一,jQuery的火热程度堪称无与伦比,简单易学的API再加丰富的插件,几乎是每个前端程序员的必修课.从读<锋利的jQuery>开始,到现在使用jQuery有一年 ...
- 《JavaScript权威指南》学习笔记之二十---XMLHttpRequest和AJAX解决方式
一.AJAX概述 AJAX是Asynchronous JavaScript and XML的缩写.中文译作异步JavaScript和XML.AJAX 不是新的编程语言,而是一种使用现有标准的新方法.在 ...
- jquery.Deferred promise解决异步回调
我们先来看一下编写AJAX编码经常遇到的几个问题: 1.由于AJAX是异步的,所有依赖AJAX返回结果的代码必需写在AJAX回调函数中.这就不可避免地形成了嵌套,ajax等异步操作越多,嵌套层次就会越 ...
- Javascript异步编程之二回调函数
上一节讲异步原理的时候基本上把回掉函数也捎带讲了一些,这节主要举几个例子来具体化一下.在开始之前,首先要明白一件事,在javascript里函数可以作为参数进行传递,这里涉及到高阶函数的概念,大家可以 ...
- js中promise解决callback回调地狱以及使用async+await异步处理的方法
1.callback回调地狱 function ajax(fn) { setTimeout(()=> { console.log('你好') fn() }, 1000) } ajax(() =& ...
- JavaScript异步编程原理
众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...
随机推荐
- Maven:Generating Project in Batch mode 卡住问题
Maven命令执行到Generating Project in Batch mode 卡住,原因是网络带宽不足问题!需要下载一个约4.1M的archetype-catalog.xml文件. Maven ...
- Socket INADDR_ANY详解
转载:http://hi.baidu.com/zorro_knight/item/37af9e8c9dc71253e73d1924 linux下的socket INADDR_ANY表示的是一个服务器上 ...
- Meanshift算法
[转载自Liqizhou],原文地址 Mean Shift算法,一般是指一个迭代的步骤,即先算出当前点的偏移均值,移动该点到其偏移均值,然后以此为新的起始点,继续移动,直到满足一定的条件结束. 1. ...
- unity 3D + Google Play In-app Billing (IAB)(转) 热度 3
最近由于工作需要,研究unity如何接入Google Play以实现游戏内购买.目前IAB的实现,prime31做的插件比较好,各平台的IAB均有,但费用相对过高(几乎都是70刀左右,可怜穷小子).在 ...
- ReflectionToStringBuilder使用
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3 ...
- FAQ:Domain Event 和 C# 中的 Event 有啥区别?
问: Domain Event 和 C# 中的 Event 有啥区别? 答: C# 中的 Event,事件.监听者列表和事件发布器是由一个类型承担,事件源和监听者之间的生命周期耦合在一起,C# 帮你提 ...
- java_Collection_详细介绍
转自:http://blog.sina.com.cn/s/blog_3fb3625f0101aref.html 1.类集框架 java.util 包中包含了一些在 Java 2 中新增加的最令人兴奋的 ...
- Java 枚举常见7种用法
用法一:常量 在JDK1.5 之前,我们定义常量都是: publicstaticfianl.....现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. publ ...
- slf4j log4j logback log4j2关系详解和相关用法
来源:slf4j log4j logback关系详解和相关用法https://www.cnblogs.com/Sinte-Beuve/p/5758971.html The Simple Logging ...
- Maven配置浅析
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...