手写Promise的API(resolve,reject,then,catch,finally,all)

在上一篇文章里,记录了手写Promise的过程 https://blog.csdn.net/m0_56698268/article/details/129815340
而Promise还有一些其他的方法,这里一起总结一下
Promise的静态方法: resolve和reject ; Promise实例上除了then,还有catch和finnaly

1、 Promise.resolve

Promise.resolve("ok")
.then((value)=>{
    
    
    console.log("promise success:", value);
},(reason)=>{
    
    
    console.log("promise fail:", reason);
})

对于上面的示例,原生的Promise肯定是返回 promise success:ok的

那在我们手写的Promise要如何实现呢?
其实就是定义一个静态方法, Promise.resolve调用时,返回一个新的Promise实例并把value抛出

static resolve(value){
    
    
    return new Promise((resolve)=>{
    
    
        resolve(value)
    })
}

再考虑更进一步,如果resolve传的不是普通值,而是一个Promise呢?
原生中实现如下代码

Promise.resolve(new Promise((resolve, reject) => {
    
    
    resolve("ok")
}))
.then((value)=>{
    
    
    console.log("promise success:", value);
},(reason)=>{
    
    
    console.log("promise fail:", reason);
})

原生中的实现肯定还是 promise success:ok
但是我们目前的Promise中,它的返回是
promise success: Promise {
status: ‘fulfilled’,
value: ‘ok’,
reason: undefined,
onFulfilledCallbacks: [],
onRejectedCallbacks: []
}

所以,我们还需要对传进来的这个value进一步解析,判断它是不是Promise
至于在哪里解析呢?其实我们可以直接在构造器定义的resolve函数里解析

		// 定义 resolve 函数
        const resolve = (value) => {
    
    
            if(value instanceof Promise){
    
    
                return value.then(resolve,reject);
            }
            if(this.status === Promise.PENDING){
    
    
                this.status = Promise.FULFILLED;
                this.value = value
                this.onFulfilledCallbacks.forEach(fn => fn())
            }
        }

整理一下这个逻辑: 我们在测试代码中,用Promise.resolve(new Promise())传了一个Promise实例(记为Pro1)进来,所以我们在定义的静态方法resolve中接收到的参数,就是这个Pro1
在这里插入图片描述
然后我们return一个自己的Promise出去(记为Pro2),调用我们构造器中定义的resolve方法
在这里插入图片描述

这里的value依旧是那个实例Pro1,接收到value先判断一下value是不是我们的Promise类型,如果确实是,那我们可以调用一下Pro1的then方法,来知道它传进来的到底是什么值。then方法接收的那个resolve就是我们返回的Pro2的那个resolve。
在这里插入图片描述
而Pro2的resolve是啥? 就是resolve(“ok”),所以它回调的值就是ok,这时候依旧是走一遍构造函数中的resolve函数,但这时候的value就是ok了,而ok不是Promise类型,所以走下面的流程,后续就和以前一样。
在这里插入图片描述

这时候 resolve方法就算实现了。 测试结果也是对的 promise success:ok


2、Promise.reject

要注意,原生Promise.reject 的处理并不是和resolve一样的

Promise.reject(Promise.resolve('ok'))
.then((value)=>{
    
    
    console.log("promise success:", value);
},(reason)=>{
    
    
    console.log("promise fail:", reason);
})

promise fail: Promise { ‘ok’ }

可以发现对于失败的处理,它如果是Promise实例,就是直接返回的
所以我们在手写中,对于失败的处理,并不需要解析它是否为Promise类型

static reject(reason){
    
    
    return new Promise((_, reject)=>{
    
    
        reject(reason)
    })
}

promise fail: Promise {
status: ‘fulfilled’,
value: ‘ok’,
reason: undefined,
onFulfilledCallbacks: [],
onRejectedCallbacks: []
}
我们测试的输出如上,其实就是基本上实现了

3、promise.then

对于promise实例上的then方法,上一篇文章中其实已经基本实现功能了,但这里还可以进一步优化一下。看下面示例:

const promise = new Promise((resolve,reject)=>{
    
    
    resolve('ok')
})

promise.then().then().then((value)=>{
    
    
    console.log("promise success:", value);
},(reason) => {
    
    
    console.log("promise fail:", reason);
});

我们在上面的代码中,连续调用then,它的结果如何呢?

promise success: ok

可是在我们手写的Promise中呢?

promise fail: TypeError: onRejected is not a function
报错了,为啥? 因为我们在then中就是定义了两个回调(成功和失败的),而测试的代码中直接then().then(),一点儿参数都不传,我们当然拿不到回调,那也当然会报错

其实原生里then().then()这种写法,其实就是无脑把value一个接一个传下去而已。
它补全后,其实我们手写的Promise也是可以执行的

promise.then((value) => {
    
    
    return value
}).then((value) => {
    
    
    return value
}).then((value) => {
    
    
    console.log("promise success:", value);
},(reason) => {
    
    
    console.log("promise fail:", reason);
});

所以,针对这一点,我们手写的Promise其实还可以优化一下

then(onFulfilled,onRejected){
    
    
        // 遇到实例中 promise.then().then().then()这种写法
        // 接收不到参数,我们进行判断,如果传回调了,不变,如果没传回调,给它补上一个函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; 
	
		......

同理,对于reject,也大同小异

const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})
promise.then().then().then((value)=>{
    
    
    console.log("promise success:", value);
},(reason) => {
    
    
    console.log("promise fail:", reason);
});

我们将其补全后,依旧可以用手写的实现

const Promise = require('./promise')
const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})

promise.then(null,(reason)=>{
    
    
    throw reason
}).then(null,(reason)=>{
    
    
    throw reason
}).then((value)=>{
    
    
    console.log("promise success:", value);
},(reason) => {
    
    
    console.log("promise fail:", reason);
});

promise fail: ok

我们再对then的onRejected回调做判断

    then(onFulfilled,onRejected){
    
    
        // 遇到实例中 promise.then().then().then()这种写法
        // 接收不到参数,我们进行判断,如果传回调了,不变,如果没传回调,给它补上一个函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; 
        onRejected = typeof onRejected === 'function' ? onRejected : (r) => {
    
    throw r}
        const promise2 = new Promise((resolve, reject)=>{
    
    

所以,这样就实现了优化。


4、promise.catch

有了then的实现,catch就会简单一些

const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})
promise.then((value)=>{
    
    
    console.log("promise success:", value);
},(reason) => {
    
    
    console.log("promise fail:", reason);
})
.catch((reason)=>{
    
    
    console.log("promise fail:", reason);
})

同样,在原生中,输出 promise fail:ok

而对于catch而言,不就是用来捕获Promise的异常的吗,那不就相当于一个没有成功的then嘛!

catch(catchCallback) {
    
    
        return this.then(null,catchCallback)
    }

测试:

const Promise = require('./promise')
const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})
promise.then((value)=>{
    
    
    console.log("promise success:", value);
})
.catch((reason)=>{
    
    
    console.log("promise fail:", reason);
})

promise fail: ok 实现成功!

5、promise.finally

Promise实例上的finally是指 无论什么情况都一定会执行,可以防止then和catch方法中的代码重复
如果返回一个 promise 会等待这个 promise 也执行完毕。如果返回的是成功的 promise,会采用上一次的结果;如果返回的是失败的 promise,会用这个失败的结果,传到 catch 中。

const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})
promise
.then((value)=>{
    
    
    console.log("promise success:", value);
})
.catch((reason)=>{
    
    
    console.log("promise fail:", reason);
})
.finally(()=>{
    
    
    console.log('finally');
})

promise fail: ok
finally

所以,我们先简单实现一下。其实就是不管成功还是失败,先执行下finally的回调,然后再返回或抛出问题

finally(finalCallback){
    
    
    return this.then((value)=>{
    
    
        finalCallback()
        return value
    },(reason)=>{
    
    
        finalCallback()
        throw reason
    })
}

promise fail: ok
finally

当然,这只是最简单的示例,如果再进一步优化呢?
为了展示问题,先把finally往前挪

const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})
promise
.finally(()=>{
    
    
    return new Promise((resolve,reject) => {
    
    
        setTimeout(()=>{
    
    
            console.log("finally");
            resolve('ok2')
        },2000)
    })
})
.then((value)=>{
    
    
    console.log("promise success:", value);
})
.catch((reason)=>{
    
    
    console.log("promise fail:", reason);
})

对于原生而言,先执行finally,遇到异步代码,等待执行完毕,然后再往下执行then
所以原生的输出是 : 等待2秒后,输出finally,然后再输出promise success:ok

而我们手写的代码执行是, 遇到finnaly中的异步代码,先往下执行then,然后再异步执行
目前手写的输出是: promise success:ok ,然后等待2秒,会输出 finally

所以,修改我们的finally函数

finally(finalCallback){
    
    
    return this.then((value)=>{
    
    
        return finalCallback().then(()=> value)
    },(reason)=>{
    
    
        return finalCallback().then(() => {
    
    throw reason})
    })
}

而在finally回调中并不是一定会返回Promise实例,如果返回123这种普通值,我们怎么处理
在finalCallback()外层包一层Promise.resolve对它进行解析

finally(finalCallback){
    
    
    return this.then((value)=>{
    
    
        return Promise.resolve(finalCallback()).then(()=> value)
    },(reason)=>{
    
    
        return Promise.resolve(finalCallback()).then(() => {
    
    throw reason})
    })
}

测试:

const Promise = require('./promise')
const promise = new Promise((resolve,reject)=>{
    
    
    reject('ok')
})
promise
.finally(()=>{
    
    
    console.log("finally");
    return 123
})
.then((value)=>{
    
    
    console.log("promise success:", value);
})
.catch((reason)=>{
    
    
    console.log("promise fail:", reason);
})

finally
promise fail: ok

6、Promise.all

promise.all是用来解决并发问题的,接收一个数组, 数组中是一个个的Promise实例对象,Promise.all会等待所以Promise实例都返回。多个异步并发获取最终的结果,但凡有一个失败就失败,所有都成功才算成功

static all(values) {
    
    
        if (!Array.isArray(values)) {
    
    
          const type = typeof values;
          return new TypeError(`TypeError: ${
      
      type} ${
      
      values} is not iterable`)
        }
        return new Promise((resolve, reject) => {
    
    
          let resultArr = [];
          let orderIndex = 0;
          const processResultByKey = (value, index) => {
    
    
            resultArr[index] = value;
            if (++orderIndex === values.length) {
    
    
                resolve(resultArr)
            }
          }
          for (let i = 0; i < values.length; i++) {
    
    
            let value = values[i];
            if (value && typeof value.then === 'function') {
    
    
              value.then((value) => {
    
    
                processResultByKey(value, i);
              }, reject);
            } else {
    
    
              processResultByKey(value, i);
            }
          }
        });
      }

测试:

const Promise = require('./promise')

let p1 = new Promise((resolve, reject) => {
    
    
    setTimeout(() => {
    
    
      resolve('ok1');
    }, 1000);
  })
  
let p2 = new Promise((resolve, reject) => {
    
    
setTimeout(() => {
    
    
    resolve('ok2');
}, 1000);
})

Promise.all([1,2,3,p1,p2]).then(data => {
    
    
	console.log('resolve', data);
}, err => {
    
    
	console.log('reject', err);
})

resolve [ 1, 2, 3, ‘ok1’, ‘ok2’ ]
当把p2改为reject时, 输出 reject ok2

一些常用API就这么多了,其余的就先不写了

猜你喜欢

转载自blog.csdn.net/m0_56698268/article/details/129850537