Promise对象
定义
promise
是一个对象,用来保存异步操作之后的结果。
promise
的状态只由异步操作的结果决定,分别有pending
(进行中)、fulfilled
(成功)、rejected
(失败)。
promise
一创建就会执行,无法取消,无法终止。
promise
提供统一的API
,各种异步操作都可以用同样的方法处理
解决了什么问题
promise
的链式调用解决了回调地狱、callback
层层嵌套的问题
promise
让代码简洁易懂,易于维护
基本用法
使用Promise()
构造函数接收一个函数作为参数,该函数的两个参数分别是resolve
和reject
。这两个参数是函数,由JavaScript
引擎提供。
const promise = new Promise((resolve,reject) => {
//write some code
if(/*异步操作成功*/){
resolve(value)
} else{
reject(error)
}
})
Promise
实例生成以后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数。
promise.then(function(success){
console.log(success)
},function(error){
console.log(error)
})
之后学了catch方法可以改写成下面这个样子
promise.then(success => {
console.log(success)
}).catch(error => {
console.log(error)
})
API
Promise.prototype.then()
promise
实例有then
方法,它接收两个函数作为参数,第一个是resolved
状态的回调函数,第二个是rejected
状态的回调函数(可选)
采用链式的then
,可以按照指定的次序调用回调函数,then
接收上一个回调函数传过来的promise
对象或者结果。
getJSON("/post/1.json").then(
post => getJSON(post.commentURL)
).then(
comments => console.log("resolved: ", comments),
err => console.log("rejected: ", err)
);
Promise.prototype.catch()
catch
方法是接收错误的回调函数,用于捕获抛出错误。
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
注意,如果在catch
前面的回调函数抛出错误,都会被catch
捕获,Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch
语句捕获。
所以,一般来说,不要在then
方法中定义reject
的回调函数,而是使用catch
方法
Promise.prototype.finally()
不管promise最后的状态是什么,finally都会执行操作
promise.then(success => {...})
.catch(error => {...})
.finally(() => {/*都会执行的操作*/})
finally
不接收任何参数,无法判断promise返回的状态是fulfilled
还是rejected
,就是说,finally
进行的操作,应与promise的状态无关,不依赖与promise返回的结果, 本质上是then
方法的特例。
Promise.all()
用于将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.all([p1,p2,p3])
Promise.all()
接收一个由Promise实例组成的数组(或者是具有Iterator接口可以遍历且返回的成员都是Promise实例的对象?)
上述代码中,p的状态由Promise实例决定,有两种情况
1、所有的promise实例状态变成fulfilled
,p的状态才变成fulfilled
,接收是一个包含各个实例结果的数组
2、其中一个promise实例的状态变成rejected
,则p的状态变成rejected
,且第一个被reject的实例返回值,会传给p的回调函数
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
上面代码中,p1
会resolved
,p2
首先会rejected
,但是p2
有自己的catch
方法,该方法返回的是一个新的 Promise 实例,p2
指向的实际上是这个实例。该实例执行完catch
方法后,也会变成resolved
,导致Promise.all()
方法参数里面的两个实例都会resolved
,因此会调用then
方法指定的回调函数,而不会调用catch
方法指定的回调函数。
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了
如果p2
没有自己的catch
方法,就会调用Promise.all()
的catch
方法。
Promise.race()
race
和all
一样,同样是将多个promise实例包装成一个新的promise实例,不同的是,哪一个promise实例最率先改变状态,那么race
将接收这个实例返回的结果传递给回调函数。
Promise.allSettled()
Promise.allSettled()
方法接受一组Promise实例作为参数,包装成一个新的Promise实例,只有等这一组实例都返回结果,即不管是fulfilled
还是rejected
,包装实例才会结束。
该包装实例的状态总是fulfilled
,接收的参数是一个包含promise实例组的解决状态和返回结果的对象数组
Promise.any()
Promise.any()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。
var resolved = Promise.resolve(42)
var rejected = Promise.reject(-1)
var alsoRejected = Promise.reject(Infinity)
Promise.any([resolved,rejected,alsoRejected]).then((result) => {
console.log(result) // 42
}).catch((error) => {
console.log(error) // [-1,Infinity]
})
Promise.resolve()
Promise.resolve()
将一个现有对象转为Promise对象。
1、参数是一个Promise实例
Promise.resolve()
将原封不动返回这个实例
2、参数是一个thenable
对象
thenable
对象是指这个对象具有then方法,如下代码所示
let thenable = {
then:function(resolved,reject){
resolved('haha')
}
}
使用Promise.resolve()
会将这个对象转为Promise对象,然后立即执行这个thenable
对象中的then方法。而转化后的promise对象的回调函数会接收thenable
对象中的then方法执行后的状态和返回的结果。
3、参数不具有then方法和对象,或根本不是对象
如果传入的参数是这种情况,那么Promise.resolve
会直接将这个传入参数转化为promise对象,并且状态为resolved,因为不存在异步操作。
4、无参数
直接返回一个resolved
状态的 Promise 对象。
需要注意的是,立即resolve()
的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。 当同时有setTimeout
和 Promise.resolve
时,resolve会先执行,因为setTimeout
是在下一轮"事件循环"开始执行的。
Promise.reject()
Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
。
注意,Promise.reject()
方法的参数,会原封不动地作为reject
的理由,变成后续方法的参数。这一点与Promise.resolve
方法不一致。
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable) // true 这个e不是“出错了”字符串,而是thenable这个对象
})
Promise.try()
应用
1、promise
与ajax
结合
2、promise
处理异步队列
3、promise
超时请求处理