手撕Promise系列五

106 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

题外话

最近复习JS,让我倍感焦虑,总感觉还有好多自己不会的东西,越学越觉得深奥,到底是谁传出去JS简单的,出来,我保证不动手~~~~

话又说回来,难也得学啊。

那就接着手撕呗,上一篇我们解决了promise循环调用的问题,到目前为止,我们解决了

then的基本搭建

then的异步处理和多次调用

then的链式调用

then的循环调用

正文

接着我们对其他的状态进行一些补充处理

  1. 当执行器当中的代码在执行过程中发生错误的时候,我们需要将promise状态变成失败状态,我们了可以使用使用try...catch来解决这个问题
  2. then里面的第一个回调函数在执行过程中报错了,要在下一个then方法中捕捉到,同样是使用try...catch来解决这个问题
  3. 之前的代码中,我们只针对then中的resolve函数进行了处理,现在处理reject失败函数的链式调用,保持和成功一致
  4. 处理异步代码,这里我们目前是把成功或者失败的回调函数直接添加进一个数组里面,我们是无法处理中途运行出错的问题。所以我们存储的时候传入一个函数,在函数里面调用回调函数。将then里面的处理代码替换掉原来的代码。resolvereject函数中也不需要传递成功或者失败的返回值了。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        //1. 使用try...catch判断同步代码在执行器中有没有在运行中发生错误,如果发生错误直接reject捕捉错误抛出
        try {
            executor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
        // executor(this.resolve, this.reject)
    }
    status = PENDING
    resp = undefined
    error = undefined
    successCallback = []
    failCallback = []
    resolve = (resp) => {
        if (this.status !== PENDING) return
        this.status = FULFILLED
        this.resp = resp
        // while (this.successCallback.length) this.successCallback.shift()(this.resp)
        //4.1 因为异步处理的代码包裹了箭头函数进行处理,并且接收了回调函数的返回值,所以这里只需要执行调用即可。
        while (this.successCallback.length) this.successCallback.shift()()
    }
    reject = (error) => {
        if (this.status !== PENDING) return
        this.status = REJECTED
        this.error = error
        // while (this.failCallback.length) this.failCallback.shift()(this.error)
        while (this.failCallback.length) this.failCallback.shift()()
    }
    then(successCallback, failCallback) {
        let promise = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    //2. then在执行过程发生错误,我们也需要通过try...catch来判断和抛出错误,给下一个then回调函数进行捕捉
                    try {
                        let result = successCallback(this.resp)
                        returnPromise(promise, result, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    //3. 同resolve
                    try {
                        let result = failCallback(this.error)
                        returnPromise(promise, result, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                // this.successCallback.push(successCallback)
                // this.failCallback.push(failCallback)
                //4. 对于异步代码运行过程中发生错误无法捕捉,我们同样也需要使用try...catch进行捕捉和抛出,所以包裹一个箭头函数进行处理
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let result = successCallback(this.resp)
                            returnPromise(promise, result, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let result = failCallback(this.error)
                            returnPromise(promise, result, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })
        return promise
    }
}

function returnPromise(promise, result, resolve, reject) {
    if (promise === result) {
        return reject('TypeError: Chaining cycle detected for promise #<Promise>')
    }
    if (result instanceof MyPromise) {
        result.then(resolve, reject)
    } else {
        resolve(result)
    }
}

结束

到目前为止,我们对then的基本处理已经完成90%了,我们下一篇将会吧then传递的两个回调函数处理为可选参数

下一篇见~~~~