1.什么是Promise
Promise是异步编程的一种解决方案。相比于回调函数更加强大、更加合理。
Promise对象的两个特点:1.Promise对象状态不受外界影响 2.状态一旦改变就不会再变
Promise对象的三种状态:1.Pending (进行中) 2.Fulfilled (已成功) 3.Rejected (已失败)。Pending只会变为Fulfilled和Rejected中的其中一种,并且只要变为其中一种状态就会凝固,不会再发生改变,这时就成为Resolved (已定型)
缺点:1. 无法取消Promise 2.如果不设置回调,内部抛出的错误不会反映到外部
2. 基本用法
const isEven = (num) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (num & 1) { // 等价于对2求余
reject(false)
} else {
resolve(true)
}
}, 2000);
})
}
isEven(3).then(res => {
console.log(res);
}).catch(err => {
console.log(err); // false
})
isEven() 返回 Promise 实例,由于传入的参数是3,所以2秒后执行 reject(false) 状态会由 Pending 变为 Rejected,之后可以通过原型上的方法then接收。因为是 reject 所以可以通过 catch 打印传来的值为 false
3. then()、catch()
这2个方法挂载在 Promise 的原型上
then:为Promise实例添加状态改变时的回调函数,then方法的第一个参数是成功的回调函数,第二个是失败的回调函数
catch:如果异步操作中抛出错误,状态则将变为Rejected,然后调用catch;在then中指定的回调函数如果运行时抛出错误,同样会被catch捕获。
4. Promise常用方法
Promise.all():将多个Promise实例包装为一个新实例
const p = Promise.all([p1, p2, p3])
// p 最后的状态由p1、p2、p3共同决定
// 1. 只有p1、p2、p3都变为成功、p最后的状态才是成功的,并返回对应的数组
// 2. 只要有一个是失败的,p就是失败的,并返回第一个失败的返回值
Promise.race():将多个Promise实例包装为一个新实例
const p = Promise.race([p1, p2, p3])
// p 最后的状态由p1、p2、p3哪个实例先改变状态决定
// 一旦其中一个实例改变了状态,那个改变状态的实例返回值传递给p的回调函数
Promise.resolve():将现有对象转为Promise对象
// 1.如果参数是Promise实例,则不作任何修改,直接返回
// 2.参数是thenable对象,如下obj就是thenable对象。resovle方法会将这个对象转为Promise对象,然后立即执行该对象的then方法。then方法执行后,对象p状态会变为resolved,从而立即执行p的then中的回调函数
const obj = {
then: function (resolve, reject) {
resolve('hi')
}
}
const p = Promise.resolve(obj)
p.then((res) => {
console.log(res);
})
// 3.不带有then方法的对象,或不是对象。返回的Promise实例状态从生成就是Resolved,所以回调函数会立即执行。
const p = Promise.resolve('hi')
p.then((res) => {
console.log(res);
})
// 4.不带任何参数:直接返回一个Resolved的Promise对象
Promise.reject():返回一个新Promise实例,状态为Rejected
const p = Promise.reject('wrong')
const p = new Promise((resolve, reject) => {
reject('wrong')
})
p.then(null, (s) => {
console.log(s)
})
5. done()、finally()的实现
done方法的实现:
Promise.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected).catch(function (reason) {
setTimeout((err) => {
throw err
}, 0);
})
}
// done的使用
isEven(3).then().catch().done()
在Promise对象的回调链的最后无论是then还是catch,只要最后一个方法抛出错误,都有可能无法捕捉到(Promise内部的错误无法冒泡到全局)。done方法会捕获到任何可能出现的错误,并向全局抛出。
finnally()方法的实现:
Promise.prototype.finally = function (callback) {
let p = this.constructor
return this.then(value => {
p.resolve(callback()).then(() => value)
}, reason => {
p.resolve(callback()).then(() => {throw reason})
})
}
// finally的使用
isEven(3).then().catch().finally(() => {
console.log('i will exec always');
})
finally方法用于指定不管Promise对象的状态如何都会执行的操作,与done方法最大的区别在于它接收一个普通的回调函数。