手写Promise/从0到1实现Promise

先贴上代码,后面是实现过程(这里不考虑很多的边界情况)

目录

一、基本调用

二、promise状态

三、传递参数

四、完善then()方法

​五、编写catch()方法

六、编写finally()方法

​​七、实现resolve()和reject()类方法

八、实现all()和allSettled()类方法

​​​九、实现race()和any()类方法


这里是全部代码,下面是实现过程

const PROMISE_STATUS = {
    PENDING: 'pending',//执行中
    FULFILLED: 'fulfilled',//成功
    REJECTED: 'rejected',//失败
}
/**
 * 捕获异常函数
 * @param {回调的方法} execFn 
 * @param {回调要传的值} value 
 * @param {成功} resolve 
 * @param {失败} reject 
 */
function executorCatch(execFn, value, resolve, reject) {
    // 如果抛出异常就执行异常
    try {
        const res = execFn(value)
        resolve()
    } catch (e) {
        reject(e)
    }
}
class P {
    constructor(executor) {
        this.status = PROMISE_STATUS.PENDING//当前状态
        this.value = undefined//成功值
        this.reason = undefined//失败值
        this.onFulfilledFun = []//有成功回调全部push进去
        this.onRejectedFun = []//有失败回调全部push进去
        const resolve = (value) => {
            if (this.status === PROMISE_STATUS.PENDING) {
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS.PENDING) return
                    this.status = PROMISE_STATUS.FULFILLED
                    this.value = value
                    this.onFulfilledFun.forEach(fn => {
                        fn(this.value)
                    })
                })

            }
        }
        const reject = (reason) => {
            if (this.status === PROMISE_STATUS.PENDING) {
                queueMicrotask(() => {
                    if (this.status !== PROMISE_STATUS.PENDING) return
                    this.status = PROMISE_STATUS.REJECTED
                    this.reason = reason
                    this.onRejectedFun.forEach(fn => {
                        fn(this.reason)
                    })
                })

            }
        }
        // 假设状态为pending也抛出异常,我们可捕获一下
        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }
    // 回调then方法
    then(onFulfilled, onRejected) {
        // 当只执行catch时,这个onFulfilled会变成undefined,就给他赋值value
        onFulfilled = onFulfilled || (value => { return value })
        onRejected = onRejected || (err => { throw new Error(err) })
        return new P((resolve, reject) => {
            if (this.status === PROMISE_STATUS.FULFILLED && onFulfilled) {
                executorCatch(onFulfilled, this.value, resolve, reject)
            }
            if (this.status === PROMISE_STATUS.REJECTED && onRejected) {
                executorCatch(onFulfilled, this.reason, resolve, reject)
            }
            if (this.status === PROMISE_STATUS.PENDING) {
                // 不是undefined的时候才push,下面同理
                if (onFulfilled) this.onFulfilledFun.push(() => {
                    executorCatch(onFulfilled, this.value, resolve, reject)
                })
                if (onRejected) this.onRejectedFun.push(() => {
                    executorCatch(onRejected, this.reason, resolve, reject)
                })
            }
        })
    }
    // 回调catch方法
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }
    // 回调finally方法,这个方法就是不论成功还是失败都会执行
    finally(onFinally) {
        this.then(() => (onFinally()), () => { onFinally() })
    }
    // 静态方法
    static resolve(value) {
        return new P(resolve => { resolve(value) })
    }
    static reject(reason) {
        return new P((resovle, reject) => { reject(reason) })
    }
    // 当全部都完成就resolve,当有未完成的就调都会调reject
    static all(promises) {
        // 重点,什么时候执行resolve,什么时候执行reject弄清楚
        return new P((resolve, reject) => {
            const values = []
            promises.forEach(promise => {
                promise.then(res => {
                    values.push(res)
                    if (values.length === promises.length) {
                        resolve(values)
                    }
                }, err => {
                    reject(err)
                })
            })
        })
    }
    // 全部返回,对的返回对的,错的就返回错的
    static allSettled(promises) {
        return new P(resolve => {
            const results = []
            promises.forEach(promise => {
                promise.then(res => {
                    results.push({ status: PROMISE_STATUS.FULFILLED, value: res })
                    if (results.length === promises.length) {
                        resolve(results)
                    }
                }).catch(e => {
                    results.push({ status: PROMISE_STATUS.REJECTED, value: e })
                    if (results.length === promises.length) {
                        reject(results)
                    }
                })
            })
        })
    }
    // 只要有结果就返回
    static race(promises) {
        return new P((resolve, reject) => {
            promises.forEach(promise => {
                // promise.then(resolve, reject)//等同于下面的代码
                promise.then(res => {
                    resolve(res)
                }), err => {
                    reject(err)
                }
            })
        })
    }
    // 一个成功,就算成功,失败收集
    static any(promises) {
        const reasons = []
        return new P((resolve, reject) => {
            promises.forEach(promise => {
                promise.then(resolve, err => {
                    reason.push(err)
                    if (reasons.length === promises.length) {
                        // 这个要用浏览器跑,我们之前一直在node下跑的
                        reject(new Aggregateerror(reasons))
                    }
                })
            })
        })
    }

}
const promise = new P((resolve, reject) => {
    console.log('状态:pending');
    resolve('111')
    // 成功了,就并不会调用下面了
    // reject('000')
})
// 回调传值
// promise.then(res => {
//     console.log('res传递的值1:', res);
//     throw new Error('我是异常')
// }, err => {
//     console.log('err传递的值1:', err);

// }).then(res => {
//     console.log('res传递的值2:', res);
// }, err => {
//     console.log('err传递的值2:', err);
// })
// promise.then(res => {
//     console.log('res传递的值:', res);
// }, err => {
//     console.log('err传递的值:', err);

// })
// 延迟一秒执行
// setTimeout(() => {
//     promise.then(res => {
//         console.log('res延迟调用', res)
//     }, err => {
//         console.log('err延迟调用', err)
//     })
// }, 1000)

// 测试catch方法
// promise.then(res => {

// }).catch(e => {
//     console.log('catch抛出的异常', e);
// })

// 测试finally方法
// promise.then(res => {
//     console.log('res传值', res);
// }).catch(e => {
//     console.log('catch抛出的异常', e);
// }).finally(() => {
//     console.log('finally');
// })

// 直接调用
// P.resolve('成功了').then(res => {
//     console.log('直接调用res', res);
// })

// P.reject('出错了').catch(e => {
//     console.log('直接调用e', e);
// })

// 模拟调用
const p1 = new P((resolve) => {
    setTimeout(() => { resolve(111) }, 1000)
})
// const p2 = new P((resolve, reject) => {
//     setTimeout(() => { reject(222) }, 2000)
// })
const p2 = new P((resolve) => {
    setTimeout(() => { resolve(222) }, 2000)
})
const p3 = new P((resolve) => {
    setTimeout(() => { resolve(333) }, 3000)
})
// P.all([p1, p2, p3]).then(res => {
//     console.log(res);
// }).catch(e => {
//     console.log(e);
// })
// P.allSettled([p1, p2, p3]).then(res => {
//     console.log(res);
// })
P.race([p1, p2, p3]).then(res => {
    console.log(res);
}).catch(e => {
    console.log(e);
})

一、基本调用

主要思路:

1. 创建一个对象,传入resolve和reject,在类中执行构造函数(每new一个对象就会执行)

2. 在构造函数中定义了两个常量放进executor方法里,然后两个常量在新建的promise中调用

这里留下的问题?我们知道promise在调用后resolve后就不会再执行reject了,我们第二点解决

二、promise状态

主要思路:

1. 定义三个常量,在构造函数中定义状态(this.status)绑定默认值pending

2. 调用resolve时,把fulfilled赋值于当前状态,就只会调用一个方法

这里留下的问题?我们怎么传递参数呢?下一点说

三、传递参数

主要思路:

1.在p类中,定义成功值和失败值,当成功时,传递过来的形参赋值this.value

                                                        当失败时,传递过来的形参赋值this.reason

2. 在p类中,定义then方法,传递两个形参命名为onFulfilled, onRejected(开发规范,尽量这样命名),然后看52行,新建的promise对象点then方法,传递两个函数,最后看17和28行,在这里调用then方法中赋值的方法

3. 使用queueMicrotask方法

queueMicrotask() - Web APIs | MDN

执行完全部代码后,再回来执行queueMicrotask(),这样就避免报错问题,看47行

(假设把this.status放到queueMicrotask()里面,会出现什么情况?即43行执行完了,还会接着执行45行的内容)

这里留下的问题?

问题1:当52-57复制一份,会执行两次吗?答案是不会的,因为在36行进行覆盖了,后面我们来解决

问题2:我们的回调传值的执行promise.then()方法还能不能接着点then()呢?

四、完善then()方法

这里有点难呀,但是这个then()写好了,后面方法都是基于这个then()的,坚持看完呀,不要慌,把这里看懂了

主要思路:

解决第三点留下的问题1,复制一份回调传值,然后在p类中定义两个数组,每次调用then()方法,就把一次回调push到这个数组,最后遍历数组执行

 如果我们再写一个延迟一秒再执行,会发现我们调用不了,为什么呢?

因为在新建的promise对象中,我们已经执行完了resolve(),那么过一秒后再执行promise.then()就会为空,怎么解决呢?

setTimeout(() => {promise.then(res => {console.log('res延迟调用', res)}, err => {console.log('err延迟调用', err)})}, 1000)

主要思路:

1. 当新建的promise对象执行完后,状态为fulfilled/rejected的时候,就可以在then中直接执行

2. 再把状态赋值放回微任务里,然后判断状态是不是pending不是的话,就不执行下面代码

 解决第三点留下的问题2,我们知道promise在执行完resolve()/reject()后如果是返回的是普通数据,那就会返回一个promise,那么就可以接着用then()回调,下面我们先写一个链式调用then()

(仔细看代码行数,下面三页是对得上的,顺序换了一下而已)

然后每次调用then()的时候,直接return一个新的promise对象,然后封装一个捕获函数,即当抛出异常就调用reject(),代码如下

可以自己测试一下,当91行注释打开后

五、编写catch()方法

主要思路:

1. 编写catch方法,传入异常,调用then(),一参为undefined,二参异常

2. 当执行then()时,一参就是第一条的undefined,不传入第二个参数,即reject为undefined

3. 当then()二参为undefined时,抛出异常

(63行之前的代码不变)

六、编写finally()方法

主要思路:

1. 定义一个finally方法,然后调用then()方法,然后把finally()的形参都放到then()形参一和形参二中

(因为不论执行reslove()还是执行reject()都会调用这个方法)

2. 回调方法做一些处理,然后测试代码

(别的代码不变)

七、实现resolve()和reject()类方法

在p类中新增,然后测试代码(其他代码不变)

八、实现all()和allSettled()类方法

在p类中新增,然后测试代码(其他代码不变) 

九、实现race()和any()类方法

 在p类中新增,然后自己测试吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值