「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。
大家好,我是L同学,最近开始总结Promise的相关知识点。本文主要介绍了Promise对象方法:then方法、catch方法和finally方法。
Promise对象方法 —— then方法
then方法是Promise对象上的方法。它其实放在Promise原型上的Promise.prototype.then。我们来看下Promise原型上有哪些方法.
console.log(Object.getOwnPropertyDescriptors(Promise.prototype));
then方法接收两个参数,一个是fulfilled的回调函数,另一个是rejected的回调函数。
promise.then(res => {
console.log(res);
}, err => {
console.log(err);
})
// 等价于
promise.then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
then方法的参数是可选的,可以不传参数,那么promise状态会一层层传递,直到传递给有回调函数的then方法。
const promise = new Promise((resolve, reject) => {
resolve(100)
})
promise.then().then().then().then(res => {
console.log(res);
})
// 相当于 将promise状态一层层传递
// promise.then(value => value).then(value => value).then(value => value).then(res => {
// console.log(res);
// })
同一个Promise的then方法可以被多次调用
当resolve回调函数被调用时,同一个Promise对象的所有then方法中的回调函数都会被调用。
const promise = new Promise((resolve, reject) => {
resolve('haha')
})
promise.then(res => {
console.log('res1', res);
})
promise.then(res => {
console.log('res2', res);
})
promise.then(res => {
console.log('res3', res);
})
then方法本身是有返回值的,返回一个Promise。如果我们在then方法中返回一个结果时,Promise会将这个结果作为resolve的参数。
resolve不同值的区别
(1) 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数。
new Promise((resolve, reject) => {
resolve('normal resolve')
}).then(res => {
console.log(res); // normal resolve
})
(2) 如果resolve传入另外一个Promise,那么这个新的Promise会决定原Promise的状态。
new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('新Promise的resolve')
},3000)
}))
}).then(res => {
// 由resolve中新传入的Promise决定
console.log(res);
})
等待3秒之后输出结果。
(3) 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行then方法,并且根据then方法的结果来决定Promise的状态。
new Promise((resolve, reject) => {
resolve({
then: function(resolve, reject) {
resolve('thenable resolve')
}
})
}).then(res => {
console.log(res); // thenable resolve
})
在then方法中,我们会返回不同的值。then方法会返回一个新的Promise对象,并将我们返回的值作为resolve回调函数的参数。然后我们需要根据上面所说的resolve不同值的区别来进行判定。
(1)then方法中,当我们返回的是一个普通值(数值/字符串/对象/undefined)时
promise.then(res => {
/* 相当于
return new Promise((resolve, reject) => {
resolve('aaa')
}) */
return 'aaa'
}).then(res => {
console.log(res); // aaa
})
(2)当我们返回的是一个Promise时
promise.then(res => {
/* 相当于
return new Promise((resolve, reject) => {
resolve(newPromise)
}) */
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1111)
}, 3000)
})
}).then(res => {
console.log(res);
})
(3)当我们返回的是一个对象,并且实现了thenable方法.
promise.then(res => {
/* 相当于
return new Promise((resolve, reject) => {
resolve({
then...
})
}) */
return {
then: function(resolve, reject) {
resolve(222)
}
}
}).then(res => {
console.log(res); // 222
})
Promise对象方法 —— catch方法
catch方法也是Promise对象上的一个方法,它也是放在Promise的原型上的Promise.prototype.catch。和then方法一样,catch方法也可以被多次调用。
const promise = new Promise((resolve, reject) => {
reject('rejected status')
})
promise.catch(err => {
console.log(err);
})
promise.catch(err => {
console.log(err);
})
promise.catch(err => {
console.log(err);
})
当executor抛出异常时,也会调用错误捕获的回调函数。
const promise = new Promise((resolve, reject) => {
// reject('rejected status')
throw new Error('rejected status')
})
promise.then(undefined, err => {
console.log(err);
console.log('------');
})
catch的返回值
catch方法也会返回一个Promise,在catch后面我们可以继续调用then方法或者catch方法。
下面的代码,后续是catch中的err2打印,还是then中的res打印呢?
const promise = new Promise((resolve, reject) => {
reject(11)
})
promise.catch(err => {
console.log('err1', err);
}).catch(err => {
console.log('err2', err);
}).then(res => {
console.log('res', res);
})
答案是then方法中的res打印,res的结果是undefined。因为第一个catch方法返回了一个新的Promise,它的resolve值是默认返回的undefined,在执行完后默认状态依旧是fulfilled,所以执行then方法。
那么我们希望后续继续执行catch呢,那么需要抛出一个异常。
promise.catch(err => {
console.log('err1', err);
throw new Error('error message')
}).then(res => {
console.log('res', res);
}).catch(err => {
console.log('err2', err);
})
我们再看下面代码的运行结果。
const promise = new Promise((resolve, reject) => {
reject('111')
})
promise.then(res => {
console.log('res', res);
}).catch(err => {
console.log('err', err);
return 'catch return value'
}).then(res => {
console.log('res result', res);
}).catch(err => {
console.log('err result', err);
})
catch方法捕获不同地方的异常
(1) catch方法捕获原Poromise的异常。
const promiseA = new Promise((resolve, reject) => {
reject('rejected status')
})
promiseA.then(res => {
return 111
}).catch(err => {
console.log('err',err); // err rejected status
})
(2) catch方法捕获新返回的Promise抛出的异常。
const promise = new Promise((resolve, reject) => {
resolve(111)
})
promise.then(res => {
return new Promise((resolve, reject) => {
reject(222)
})
}).catch(err => {
console.log('err',err); // err 222
})
常见错误
当写成以下代码时,会出现错误。这是因为then方法和catch方法是独立的,互不影响。当调用reject回调函数时,没有对错误进行捕获。
const promise = new Promise((resolve, reject) => {
reject(111)
})
promise.then(res => {
console.log(res);
})
promise.catch(err => {
console.log(err);
})
Promise对象方法 —— finally
finally方法是ES9新增的特性。finally方法不接收参数,表示Promise对象无论变成fulfilled状态还是reject状态,最后都会被执行的代码。
const promise = new Promise((resolve, reject) => {
// resolve('resolve message')
reject('reject message')
})
promise.then(res => {
console.log('res', res);
}).catch(err => {
console.log('err', err);
}).finally(() => {
console.log('finally');
})
finally方法后面可以链式调用then方法来拿到当前Promise对象最终返回的结果。
function p1() {
return new Promise((resolve, reject) => {
resolve(100)
})
}
p1().finally(() => {
console.log('finally');
}).then(res => console.log(res))
往期文章 👇👇👇