JavaScript中的Promise对象

Promise是ES6中新增的一种特性,是异步编程的一种解决方案,相比于回调函数与事件更合理而且更加强大,可以用来解决“回调地狱”问题。

最早由社区提出并实现,ES6将它写入了语言标准,统一了用法,并原生提供了Promise对象。

尽管用过基于Promise的Axios,但是对于Promise本身我却知之甚少。所以这里把它学一学。这篇学习笔记摘自《ECMAScript标准入门》第十四章。

Promise是啥?可以把它理解为用于处理异步事件的一种容器,保存着某个未来才会结束的事件的结果。它本质上是一个对象,从它可以获取异步操作的消息。它提供了统一的API,可以适用于各种情况下的异步操作。

对于一个Promise对象,它有两个特点:

  • 对象状态不受外界影响。它有三种状态:pendingfulfilledrejected,分别代表进行中,已成功,已失败,这三种状态只有异步操作的结果才可以改变,其他任何操作都对它不会造成影响,这也是英文名Promise的由来,代表“承诺”或者“期约”(红宝书译者李松峰先生翻译为期约)。
  • 一旦状态改变了,那就不会再改变,任何时候都可以获得这个结果。Promise的状态改变只有两种可能,即从pending变成fulfilled或从pending变成rejected,一旦改变,此时结果将定型,这时将状态称之为resolved。与事件不同,事件在错过之后,监听将无法得到结果,但Promise可以随时通过回调函数获取到已经resolved的结果。

Promise可以将嵌套调用的异步回调函数变成同步操作的流程,这并不是说把异步改成了同步,而是使用同步的形式,内部其实仍然是异步的。这个特性可以处理掉回调地狱这个问题。

Promise的缺点是:

  • 无法取消,一旦新建将被立即执行
  • 如果不设置回调函数,内部的错误不会抛到外部
  • pending阶段时无法得知具体pending到哪个程度

一个简单的Promise实例:

1
2
3
4
5
6
7
let promise = new Promise((resolve, reject) => {
// do something
if (success)
resolve(val);
else
reject(err);
})

它接受一个函数作为参数,这个函数的两个参数一个是resolve一个是reject,这两个函数JavaScript引擎会提供。

走resolve就变成功,走reject就变失败。可以使用.then方法指定两个回调函数,这两个回调函数前者代表成功时执行,后者代表失败时执行,第二个回调函数可以不写。then方法指定的回调函数将在当前脚本所有同步任务执行完之后才会执行,所以假如有三个log,一个在promise定义,一个在then,一个在外部,则输出顺序是promise 外部 then。在调用resolve或reject的时候如果带了参,这些参会被原封不动的传到回调函数里。reject函数的参数通常是Error对象的实例,表示抛了错误。

使用promise封装ajax操作,可以避免多次网络请求的回调地狱,但其实我们做项目用的时候直接上Axios多一点,有的地方用fetch API,也不错。

.catch方法是.then的别名,一般用于处理错误。如果异步操作走到了reject,那就会用catch方法指定的回调函数处理这个错误,如果在then里面运行时报错了,也会走catch。但当这个promise已经resolved之后,再抛出错误,也不会被捕获了。它的错误有冒泡性质,会一直向下传递,直到被下一个catch抓到。

1
2
3
4
5
6
7
8
9
10
11
12
let promise = new Promise((resolve, reject) => {
try {
throw new Error('err!');
}
catch (e) {
reject(e);
}
});

promise.catch(err => {
console.log(err);
})

一般而言,不使用then中的第二个参数,而是使用catch方法。

Promise.all()方法用于将多个Promise实例封装成一个新的Promise实例,接受一个数组作为参数,数组里的元素都是Promise的实例,如果不是,就会先调用Promise.resolve()方法转化为Promise。

比如使用all方法生成了一个p,p里面有p1,p2,p3三个Promise实例,p是一个Promise,所以p的状态只跟p1p2p3有关。判定规则如下:当三者全都fulfilled,则p也会fulfilled;如果有其中一个reject,那p就reject,第一个被reject的实例会返回值给p的回调。

还有一个类似的方法叫做Promise.race(),传参和all相同,但里面的实例有一个改变状态,封装好的Promise实例就改变状态,改变相同。

还有两个有用的附加方法,第一个是done(),用于解决最后一个方法抛出的错误无法捕捉,done方法永远处于回调链的尾端,保证抛出任何可能出现的错误。done方法也可以像then那样提供传参,也可以不传任何东西。第二个是finally,指定无论Promise对象最后状态如何都会执行的操作,它接受一个回调函数作为必要参数,无论怎样都要执行。

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2018-2021 Shawn Zhou
  • Hexo 框架强力驱动 | 主题 - Ayer
  • 访问人数: | 浏览次数:

感谢打赏~

支付宝
微信