我们先来看一下编写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解决方式相关推荐

  1. 使用promise解决回调地狱_回调地狱的由来和如何利用promise解决回调地狱

    var fs =require('fs') fs.readFile('./a.txt', 'utf8',function(err,data){ if(err){ console.log('读取失败') ...

  2. 写好 JavaScript 异步代码的几个技巧

    今天给大家来推荐几个写好 JavaScript 异步代码的推荐做法,每种场景都有一个对应的 eslint 规则,大家可以选择去配置一下. no-async-promise-executor 不建议将 ...

  3. javascript之异步操作理解---回调函数,async,await以及promise对象

    javascript之异步操作理解---回调函数,async,await以及promise对象 概述 概述 写在前面:虽然平时做项目,但是发现自己写的代码还是很烂.最近接触了一个对性能要求比较高的项目 ...

  4. javascript异步中的回调

    同期异步系列文章推荐 谈一谈javascript异步 javascript异步与promise javascript异步之Promise.all().Promise.race().Promise.fi ...

  5. 将回调地狱按在地上摩擦的Promise

    这是一段旁白 "异步虐我千百遍,我待异步如初恋"!! 做前端的同学做异步肯定都不陌生.因为JavaScript是单线程语言(也就是说不支持多线程编程,这不是废话么啊喂!),所以在J ...

  6. ajax回调函数ifelse,实现AJAX及用Promise解决回调函数命名问题

    html代码: js代码: window.jQuery=function(){} window.jQuery.ajax = function({method, url, body, headers, ...

  7. 什么是回调地狱?如何解决回调地狱

    一.什么是回调地狱呢? 地狱这个词不陌生吧!对,没错就是那个十八层地狱的地狱,一层一层的地狱. 1.同步API,异步API的区别 这个问题呢,需要从Node.js的API说起,这里就会有人问了?博主你 ...

  8. Promise相关内容(三)——异步获取服务器数据:promise方式解决回调地狱的问题。通过多个.then使代码可读性更高 实现异步任务的串行执行,保证按顺序发送请求获取数据

    Promise相关内容(三)--异步获取服务器数据:promise方式解决回调地狱的问题.通过多个.then使代码可读性更高 & 实现异步任务的串行执行,保证按顺序发送请求获取数据 第一种形式 ...

  9. 【JavaScript】同步与异步-异步与并行-异步运行机制-为什么要异步编程-异步与回调-回调地狱-JavaScript中的异步操作

    文章目录 1. 同步与异步 1.1 同步行为synchronous 1.1.1 特点 1.1.2 例子 1.2 异步行为asynchronous 1.2.1 必要性 1.2.2 特点 1.2.3 例子 ...

  10. 【JavaScript】回调地狱、Promise

    文章目录 1. 回调函数 2. 异步任务 3. 回调地狱 4. Promise 4.1 Promise定义 4.2 Promise基础用法 4.2.1 生成Promise实例 4.2.2 Promis ...

最新文章

  1. Linux chmod给文件加执行X权限
  2. SQL Server分页查询存储过程
  3. [SCOI2012] 喵星球上的点名
  4. ELF格式解析库之基本数据类型
  5. linux编写设备驱动 编译成ko文件 重新编译内核,Linux内核驱动将多个C文件编译成一个ko文件的方法——每一个C文件中都有module_init与module_exit...
  6. 番茄助手破解找到VA_X.dll的位置
  7. Ubuntu下安装的qq的下载文件地址
  8. 小技巧:不显示打印对话框直接打印网页到打印机
  9. Ubuntu真心不太适合搞开发啊
  10. 医学图像处理涉及到的窗宽窗位 1
  11. webp文件怎么打开?webp压缩工具推荐
  12. 搜索技术——遗传算法
  13. 【Linux系统】第9节 linux系统中用户分类以及用户与组属性的修改示例
  14. 以前学习C语言资料2
  15. 微信小程序跳转外链,打开视频号及小程序内跳转方法
  16. 数据中心的节能减排之路
  17. 麻瓜+AI混合工作流试验 8:周末瞎想…… 如何跨界学习/知识迁移
  18. 用HTML+CSS做一个简单的美食网页---web学生网页设计作业源码
  19. nohup: 重定向标准错误到标准输出
  20. 中山大学智能发票识别系统

热门文章

  1. python selenium 常用方法
  2. php解析html类库simple_html_dom(2)
  3. configure: error: gperf is needed
  4. 制作LINUX安装DEB,脚本中的函数报错怎么办?
  5. hg diff仅对当前目录下的文件有效
  6. 由古书看,古人应该知道地球是圆的
  7. 面试记录:面试两个人的不同结果
  8. 在函数‘_start’中:对‘main’未定义的引用
  9. C++中Vector/Map/List中尽量使用指针,避免直接保存对象
  10. FireFox使用百度网盘插件