在Web前端开发中,我们使用JavaScript会大量依赖异步计算。比如说,Ajax请求时,我们可能会需要不只一个请求来达到某种目的,此时需要后面的请求依赖于前面请求的结果。这种情况在简单的业务中并无大碍,但当我们遇到多个请求时,为了保证依赖顺序,必须进行嵌套,臃肿的代码就是我们常说的“回调地狱”问题。为了解决问题,ES6根据Promise/A+推出了Promise语法。

文章目录

  • 1. 简单运用Promise
  • 2. Promise三个状态
  • 3. Promise链式调用
  • 4. Promise.all
  • 5. Promise.race
  • 6. Axios——Promise封装的Ajax
  • 7. async/await

1. 简单运用Promise

function sleep(time) {return new Promise(function(resolve, reject) {if(time < 1000) {setTimeout(resolve("You are success"), time);}else {reject("fail");}})
}sleep(500).then(msg => {console.log(msg);
}).catch(err => {console.log(err);
});

控制台查看结果:

一般在使用Promise的时候,会在定义的函数中返回一个Promise构造函数,该构造函数包含两个参数,分别是resolve和reject。在上面的代码中,我们调用sleep方法,传入500。而我们使用了Promise的内置方法then,并且向then中传两个参数,一个是成功回调函数,一个是失败回调函数(本例中省略第二个参数)。当承诺成功兑现,第一个回调就会被调用,而当出现错误的时候,就会调用第二个参数reject(此处省略)。由于500小于1000,因此会执行setTimeout(resolve(“You are success”), time),输出了You are success。
在上面的例子中,我们还使用了Promise中的catch方法,当传入的参数大于500,则会执行catch方法,catch方法中传递一个参数,也就是reject,因此在失败的时候会执行它。如下:

2. Promise三个状态

promise对象用于作为异步任务结果的占位符,代表着一个我们暂时还没获得但未来有希望获得的值。正是因为这个原因,js的工程师们为Promise设置了三种状态,分别是等待态(pending),接受态(fullfilled),失败态(rejected)。当resolve函数被调用,promise的状态就会变成接受态;反之,如果reject方法被调用,或者在promise调用过程中发生了一个未处理的异常,则会进入失败态。一旦状态改变一次,promise将不会再次改变状态。

3. Promise链式调用

在本文开头,我们提到了回调地狱,最为常见的就是使用Ajax时,由于多个相互关联的请求多层嵌套,造成语法臃肿,对于后续的维护产生了不好的影响。而promise的链式调用,一定程度上解决了这个问题。我们再回到代码:

sleep(500).then(msg => {console.log(msg);
}).catch(err => {console.log(err);
});

此处使用了then方法,当promise成功兑现,则触发回调函数。我们还会发现,除了打印出You are success之外,还返回了一个Promise对象。

这就是说,每次then()都会返回一个新的promise,而这一个promise则可以交给下一个then方法使用。如下所示,每次then方法之后都返回了sleep(),而我们给出的sleep方法就是返回一个promise实例化对象,这样不断交给下一个then方法执行,就是我们的链式调用。

sleep(500)
.then(msg => {console.log(msg);return sleep(500);
})
.then(msg => {console.log(msg);return sleep(500);
})
.then(msg => {console.log(msg);return sleep(500);
})
.then(msg => {console.log(msg);return sleep(1500);
})
.catch(err => {console.log(err);
});

控制台输出:

4. Promise.all

Promise除了链式调用实现多个步骤相互依赖之外,还提供了同时等待多个异步任务的方法,这里使用Promise中的all。

Promise.all([ sleep(500), sleep(600), sleep(1500)]).then(result => {console.log(result);}).catch(err => {console.log(err);})

控制台输出如下:

在这个方法的使用中,我们不关系任务执行的顺序。使用的时候,我们传入一个数组,元素则是promise对象。当调用all的时候,会等待所有的promise对象被兑现之后,返回一个成功值数组。
但是,当其中一个promise失败,则会影响整个结果,如下所示:

5. Promise.race

当我们只关心第一个返回结果的promise时,Promise.race能帮你达成这个愿望。如同Promise.all一样,我们在使用race的时候会传入一个promise对象数组,,一旦该数组中的一个promise被兑现,则返回结果。为了印证这一点,我们改造一下sleep方法,如下:

function sleep(time) {return new Promise(function(resolve, reject) {if(time < 1000) {setTimeout(resolve(`${time}s later...`), time);}else {reject("fail");}})
}Promise.race([ sleep(500), sleep(600), sleep(700)]).then(result => {console.log(result);})

控制台输出如下:

6. Axios——Promise封装的Ajax

在前端开发中,异步向后端发起请求有很多中方法,jQuery的Ajax,fetch,以及axios。axios的官网(http://www.axios-js.com/zh-cn/docs/)上是这样介绍的。

和jQuery的Ajax功能相似,都是对XMLHttpRequest的封装,让我们能够更好地进行异步请求。在Axios官网中还提到:“使用Promise管理异步,告别传统callback方式”,这里说的就是Promise的链式调用。正是这种语法的使用,让回调地狱问题得到了很好的解决。axios本质上也是对原生XHR的封装,只不过它是Promise的实现版本。
Axios简单使用代码如下:

axios.get(url).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});

本质上Axios的实例化对象就是一个promise,因此当我们熟悉了promise之后再来使用axios会比较容易上手。
为了加深理解,这里使用Promise封装一个XMLHttpRequest,模拟axios。代码如下:

function getJSON (url) {return new Promise( (resolve, reject) => {var xhr = new XMLHttpRequest()xhr.open('GET', url, true)xhr.onreadystatechange = () => {if (this.readyState === 4) {if (this.status === 200) {resolve(this.responseText)} else {var resJson = { code: this.status, response: this.response }reject(resJson, this)}}}xhr.send()})
}getJSON ("https://blog.csdn.net/").then(res => {console.log(res); }).catch(error => {console.error(error);});

非常遗憾,出现了跨域问题,但是没关系,主要是通过一个实际的例子让帮助大家更进一步理解promise。

7. async/await

不知道大家发现没有,Promise虽然一定程度上解决了回调地狱问题,但是链式调用的语法仍然不够优雅,我们如果能用完全同步的语法来解决异步问题,那该有多好。在ES6中,我们可以使用生成器和promise相结合的方式实现这个愿望。而JS伟大的工程师们为我们提出了更好的方案,async/await,这号称是JavaScript解决异步问题的终极解决方案,其实是对Promise的再一次封装,也可以说是语法糖。那么它到底如何,就请听下回分解吧!

回调地狱终结者——Promise相关推荐

  1. 【JavaScript】回调地狱、Promise

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

  2. 详解回调地狱以及promise

    1.什么是回调地狱? 说promise之前必须先简单说下,回调地狱 回调地狱:在回调函数中又嵌套了多层回调函数,便会形成回调地狱 JS中或node中,都大量的使用了回调函数进行异步操作,而异步操作什么 ...

  3. ES6(三)——回调地狱和promise异步任务顺序执行(传参、错误处理)

    文章目录 方法一.回调函数(回调地狱) 方法二:promise 2.1异步任务传参(单个) 2.2异步任务传参(多个) 2.3 错误处理 2.4 Promiss对象三大状态: (学名) 2.5 Pro ...

  4. 回调地狱和Promise

    目录 1.回调地狱callback-hell 由于fs.readFile是异步操作,所以你不能判断下面三个文件的执行顺序 var fs = require('fs')fs.readFile('./da ...

  5. 回调地狱与promise

    <script src="js/ajax.js"></script><script>// function fn(a){// a()// }// ...

  6. 什么是回调地狱以及promise的链式调用和aysnc/await

    上面一篇博客写到了回调地域的问题,这篇博客将深究这个词语,如下例: doSomething(function(result){doSomethingElse(result, function(newR ...

  7. 【Callback Hell】一文让你轻松了解何为回调地狱?

    回调地狱[Callback Hell] 前提知识点: 单线程和异步: JS是单线程语言,只能同时做一件事儿 (例子:做一个ajax请求去加载资源,或者说弄一个定时器,先等待1秒钟后干嘛,如果按照单线程 ...

  8. 一文告诉你什么是回调地狱,如何解决回调地狱?

    文章目录 前言 一.回调地狱是什么? 二.如何解决回调地狱 1.Promise 2.async/await 总结 前言 在正式了解"回调地狱"之前,我们先了解两个概念: 回调函数 ...

  9. 使用ES6的Promise完美解决回调地狱

    相信经常使用ajax的前端小伙伴,都会遇到这样的困境:一个接口的参数会需要使用另一个接口获取. 年轻的前端可能会用同步去解决(笑~),因为我也这么干过,但是极度影响性能和用户体验. 正常的前端会把接口 ...

最新文章

  1. VC中基于 Windows 的精确定时
  2. pygame 移开的矩形留痕迹_Python之pygame学习矩形区域(5)
  3. 基于PYNQ-Z2实现BNN硬件加速
  4. vlookup练习_那个vlookup,我总是学不会啊
  5. 彩虹六号服务器显示,彩虹六号怎么看自己在什么服务器 | 手游网游页游攻略大全...
  6. java数据结构期末复习_java数据结构复习02
  7. 【华为云技术分享】数据管理服务DAS 之 数据库自动化运维功能展播4:慢SQL
  8. P1322 logo语言
  9. CSS-table样式+
  10. 缺少计算机所需的介质程序,win10系统UEFi安装提示“缺少计算机所需的介质驱动程序”的图文方案...
  11. 碰到高速下载器捆绑软件自动下载,卸载不完怎么办?
  12. rrpp协议如何修改_华为交换机―RRPP协议
  13. Mac 从命令行启动模拟器
  14. 通过站点优化记录规划书
  15. Eclipse中设置jsp文件 字体大小
  16. Linux 文件系统(2)sda sdb 和 SATA IDE SCSI
  17. Josephus问题(最后一个退出的人)
  18. RabbitTMQ实战 高效部署分布式消息队列笔记
  19. js进入页面后自动触发点击事件
  20. 淘宝联盟开发系列:阿里妈妈淘宝客申请步骤

热门文章

  1. 如何在 YouTube 上打开或关闭评论
  2. scp:windows与linux之间copy文件(类似于linux的scp工具)
  3. Arduino数码管时钟演示
  4. linux_sw_64,鳥哥的 Linux 私房菜
  5. svn切换账号的问题
  6. self_drive car_学习笔记--第10课:路径规划
  7. 服务机器人市场发展综述及细分领域发展情况
  8. 人人商城(分销版)1.11.7微擎原版,提示“抱歉,您无权进行该操作,请先登录!”只因为一个字母,我苦找了9个多小时。
  9. Online Meeting
  10. 纽马克-贝塔法(Newmark-Beta Method)原理