为何用Promise?
我们平时不怎么会遇到回调嵌套很多层的情况,一般也就是一到二级,但是如果遇到回调嵌套很多时,代码层面看会很繁琐,这种情况我们一般称----回调地狱。极端情况如下图:
由此,Promise的概念最早由社区提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。作用与回调方法几乎一致,都是在某种情况下执行预先设定好的方法,但是使用它却能够让代码变得更简洁清晰。
什么是Promise?
复杂的概念我们先不讲,我们先直观的看一下promise是个什么东西呢?这时候我们直接在控制台打印出来看一下吧:console.dir(Promise):
我们一看结果就可以看出来,Promise本身是一个构造函数,它自身和原型上都提供了几个api。
Promise翻译过来是表示“承诺”:承诺将来会执行。
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
基本用法
下面代码创造了一个Promise实例。
const promise = new Promise((resolve, reject)=> {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将状态由“未完成”变为“成功”,将异步成功操作的结果,作为参数传递出去;
reject函数的作用是,将状态由“未完成”变为“失败”,将异步错误操作的结果,作为参数传递出去;
Promise实例的常用方法
Promise.resolve()
Promise.resolve()旨在将现有对象转换成Promise对象。
Promise.resolve等价于下面的写法。
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。
Promise.prototype.then()
Promise实例具有then
方法,从我们上面console的结果可以看出,then
是定义在原型对象Promise.prototype上的;它的作用是为 Promise 实例添加状态改变时的回调函数。
then
方法可以接受两个回调函数作为参数,第一个参数是成功的回调,第二个参数是失败的回调,其中,第二个参数是可选的。这两个函数都接受Promise对象传出的值作为参数。可以由上面生成的promise实例来简单举个例子:
promise.then((value) =>{
// success
},(error) =>{
// failure
});
then
方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then
方法后面再调用另一个then
方法。
promise.then((value) =>{
// success
},(error) =>{
// failure
}).then();
Promise.prototype.catch()
Promise.prototype.catch
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
一般都会使用catch来捕获promise的错误回调结果,但是最好不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
// bad
promise
.then((data)=> {
// success
},(err)=> {
// error
});
// good
promise
.then((data)=> { //cb
// success
})
.catch((err)=> {
// error
});
Promise.prototype.all()
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)
Promise.prototype.finally()
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally本质上是then方法的特例。