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());//pendingvar 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解决方式相关推荐
- 使用promise解决回调地狱_回调地狱的由来和如何利用promise解决回调地狱
var fs =require('fs') fs.readFile('./a.txt', 'utf8',function(err,data){ if(err){ console.log('读取失败') ...
- 写好 JavaScript 异步代码的几个技巧
今天给大家来推荐几个写好 JavaScript 异步代码的推荐做法,每种场景都有一个对应的 eslint 规则,大家可以选择去配置一下. no-async-promise-executor 不建议将 ...
- javascript之异步操作理解---回调函数,async,await以及promise对象
javascript之异步操作理解---回调函数,async,await以及promise对象 概述 概述 写在前面:虽然平时做项目,但是发现自己写的代码还是很烂.最近接触了一个对性能要求比较高的项目 ...
- javascript异步中的回调
同期异步系列文章推荐 谈一谈javascript异步 javascript异步与promise javascript异步之Promise.all().Promise.race().Promise.fi ...
- 将回调地狱按在地上摩擦的Promise
这是一段旁白 "异步虐我千百遍,我待异步如初恋"!! 做前端的同学做异步肯定都不陌生.因为JavaScript是单线程语言(也就是说不支持多线程编程,这不是废话么啊喂!),所以在J ...
- ajax回调函数ifelse,实现AJAX及用Promise解决回调函数命名问题
html代码: js代码: window.jQuery=function(){} window.jQuery.ajax = function({method, url, body, headers, ...
- 什么是回调地狱?如何解决回调地狱
一.什么是回调地狱呢? 地狱这个词不陌生吧!对,没错就是那个十八层地狱的地狱,一层一层的地狱. 1.同步API,异步API的区别 这个问题呢,需要从Node.js的API说起,这里就会有人问了?博主你 ...
- Promise相关内容(三)——异步获取服务器数据:promise方式解决回调地狱的问题。通过多个.then使代码可读性更高 实现异步任务的串行执行,保证按顺序发送请求获取数据
Promise相关内容(三)--异步获取服务器数据:promise方式解决回调地狱的问题.通过多个.then使代码可读性更高 & 实现异步任务的串行执行,保证按顺序发送请求获取数据 第一种形式 ...
- 【JavaScript】同步与异步-异步与并行-异步运行机制-为什么要异步编程-异步与回调-回调地狱-JavaScript中的异步操作
文章目录 1. 同步与异步 1.1 同步行为synchronous 1.1.1 特点 1.1.2 例子 1.2 异步行为asynchronous 1.2.1 必要性 1.2.2 特点 1.2.3 例子 ...
- 【JavaScript】回调地狱、Promise
文章目录 1. 回调函数 2. 异步任务 3. 回调地狱 4. Promise 4.1 Promise定义 4.2 Promise基础用法 4.2.1 生成Promise实例 4.2.2 Promis ...
最新文章
- Linux chmod给文件加执行X权限
- SQL Server分页查询存储过程
- [SCOI2012] 喵星球上的点名
- ELF格式解析库之基本数据类型
- linux编写设备驱动 编译成ko文件 重新编译内核,Linux内核驱动将多个C文件编译成一个ko文件的方法——每一个C文件中都有module_init与module_exit...
- 番茄助手破解找到VA_X.dll的位置
- Ubuntu下安装的qq的下载文件地址
- 小技巧:不显示打印对话框直接打印网页到打印机
- Ubuntu真心不太适合搞开发啊
- 医学图像处理涉及到的窗宽窗位 1
- webp文件怎么打开?webp压缩工具推荐
- 搜索技术——遗传算法
- 【Linux系统】第9节 linux系统中用户分类以及用户与组属性的修改示例
- 以前学习C语言资料2
- 微信小程序跳转外链,打开视频号及小程序内跳转方法
- 数据中心的节能减排之路
- 麻瓜+AI混合工作流试验 8:周末瞎想…… 如何跨界学习/知识迁移
- 用HTML+CSS做一个简单的美食网页---web学生网页设计作业源码
- nohup: 重定向标准错误到标准输出
- 中山大学智能发票识别系统
热门文章
- python selenium 常用方法
- php解析html类库simple_html_dom(2)
- configure: error: gperf is needed
- 制作LINUX安装DEB,脚本中的函数报错怎么办?
- hg diff仅对当前目录下的文件有效
- 由古书看,古人应该知道地球是圆的
- 面试记录:面试两个人的不同结果
- 在函数‘_start’中:对‘main’未定义的引用
- C++中Vector/Map/List中尽量使用指针,避免直接保存对象
- FireFox使用百度网盘插件