携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
前言
本篇将讲解Promise.prototype.catch以及Promise.prototype.finally的细则以及实现,希望通过阅读这篇文章能让你完全掌握。
阅读这篇文章,需要你掌握的知识👇
- Promise基本知识
其中Promise基础知识如果不了解或有遗忘的同学可以参考我这篇文章:《简单明了的Promise基本知识点》
本文需要使用的实现类代码👇
class myPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(func){
this.PromiseState = myPromise.PENDING
this.PromiseResult = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
try{
func(this.resolve.bind(this),this.reject.bind(this))
}catch (e){
this.reject(e)
}
}
resolve(result){
if(this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.FULFILLED
this.PromiseResult = result
setTimeout(()=>{
this.onFulfilledCallbacks.forEach(callback=>{callback(result)})
})
}
}
reject(reason){
if (this.PromiseState == myPromise.PENDING){
this.PromiseState = myPromise.REJECTED
this.PromiseResult = reason
setTimeout(()=>{
this.onRejectedCallbacks.forEach(callback=>{callback(reason)})
})
}
}
then(onFulfilled,onRejected){
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value
onRejected = typeof onRejected == 'function' ? onRejected : reason =>{ throw reason }
const promise2 = new myPromise((resolve,reject)=>{
if (this.PromiseState == myPromise.FULFILLED){
setTimeout(()=>{
try {
const value = onFulfilled(this.PromiseResult)
if (value != undefined){
resolvePromise(promise2,value,resolve,reject)
}
}catch (e){
reject(e)
}
})
}else if(this.PromiseState == myPromise.REJECTED){
setTimeout(()=>{
try {
const value = onRejected(this.PromiseResult)
if (value != undefined){
resolvePromise(promise2,value,resolve,reject)
}
}catch (e){
reject(e)
}
})
}else if(this.PromiseState === myPromise.PENDING){
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
})
return promise2
}
}
function resolvePromise(promise2,x,resolve,reject){
if (promise2 == x){
return reject(new TypeError())
}
//2.3.2判断传入参数是否为Promise
if (x instanceof myPromise){
//2.3.2.1 如果 `x` 处于等待状态, `promise` 需保持为等待态直至 `x` 被执行或拒绝
if (x.PromiseState == myPromise.PENDING){
resolvePromise(promise2,x,resolve,reject)
}else if(x.PromiseState == myPromise.FULFILLED){
// 2.3.2.2 如果 x 处于执行态,用相同的值执行 promise
resolve(x.PromiseResult);
}else if (x.PromiseState === myPromise.REJECTED) {
// 2.3.2.3 如果 x 处于拒绝态,用相同的据因拒绝 promise
reject(x.PromiseResult);
}
}else if(x != null && (typeof x === 'object' || typeof x == 'function')){
let then;
try {
then = x.then
}catch (e) {
reject(e)
}
if (typeof then == 'function'){
//2.3.3.3.3 如果 `resolvePromise` 和 `rejectPromise` 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
let called = false
try{
then.call(x,
// 2.3.3.3.1 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y =>{
if (called)return //如果已调用,则采取首次调用
called = true
resolvePromise(promise2, y, resolve, reject);
},
// 2.3.3.3.2 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r =>{
if (called)return //如果已调用,则采取首次调用
called = true
reject(r);
})
}catch (e) {
//2.3.3.3.4 如果调用 `then` 方法抛出了异常 `e`:
//2.3.3.3.4.1 如果 `resolvePromise` 或 `rejectPromise` 已经被调用,则忽略之
if (called)return
//2.3.3.3.4.2 否则以 `e` 为据因拒绝 `promise`
called = true
reject(e)
}
}else{
//2.3.3.4 如果 `then` 不是函数,以 `x` 为参数执行 `promise`
resolve(x)
}
}
}
什么是Promise.prototype.catch?
Promise.prototype.catch作为Promise类实例属性具有的方法,
- 接收一个回调函数参数
Promise.prototype.catch返回一个Promise,并且处理拒绝的情况。- 它的行为与调用
Promise.prototype.then(undefined, onRejected)相同。
实现 Promise.prototype.catch
class myPromise {
...
then(onFulfilled, onRejected) {
...
}
catch (onRejected) {
return this.then(undefined, onRejected)
}
}
如上代码为什么这么简单?
由于官方规定catch(onRejected)与调用Promise.prototype.then(undefined, onRejected) 相同。
我们只好这么写咯🤡
测试代码
const myPromise = require('./promiseOtherAPI')
var p1 = new myPromise(function (resolve, reject) {
resolve('Success');
});
p1.then(function (value) {
console.log(value); // "Success!"
throw 'oh, no!';
}).catch(function (e) {
console.log(e); // "oh, no!"
}).then(function () {
console.log('after a catch the chain is restored');
}, function () {
console.log('Not fired due to the catch');
});
// 以下行为与上述相同
p1.then(function (value) {
console.log(value); // "Success!"
return Promise.reject('oh, no!');
}).catch(function (e) {
console.log(e); // "oh, no!"
}).then(function () {
console.log('after a catch the chain is restored');
}, function () {
console.log('Not fired due to the catch');
});
// 捕获异常
const p2 = new myPromise(function (resolve, reject) {
throw new Error('test');
});
p2.catch(function (error) {
console.log(error);
});
// Error: test
控制台结果👇
Success
Success
Error: test
oh, no!
oh, no!
after a catch the chain is restored
after a catch the chain is restored
如果你的输出结果和以上一致,就代表测试通过了🤩
什么是Promise.prototype.finally?
Promise.prototype.finally作为Promise类实例属性具有的方法,
- 接收一个回调函数作为参数
- 返回一个
Promise - 在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。
实现 Promise.prototype.finally
class myPromise {
...
/**
* finally
* @param {*} callBack 无论结果是fulfilled或者是rejected,都会执行的回调函数
* @returns
*/
finally(callBack) {
return this.then(callBack, callBack)
}
}
如上代码中,由于finally方法不用参考执行时Promise的状态,但又会返回一个新的Promise并且执行回调函数。于是我们可以巧妙的使用then方法,从而达到了
- 异步执行
- 参数校验
- 返回一个符合规范的
Promise
测试代码
const myPromise = require('./promiseOtherAPI')
let p1 = new Promise(function (resolve, reject) {
resolve(1)
}).then(function (value) {
console.log(value);
}).catch(function (e) {
console.log(e);
}).finally(function () {
console.log('finally');
});
输出结果:
1
finally
如果你的输出结果和以上一致,就代表测试通过了🤩
尾声
这俩个api的实现较为简单,我就合着一篇文章一起讲解了。越写越发现实现Promise系列的难点是去记这么多规则了,希望同学们牢记规则。
\