实现一个Promise

本文根据Promise A+规范详细讲解如何封装一个Promise,重点介绍准备状态和Promise实例的方法如then、catch、finally。虽然与v8引擎的Promise行为有差异,但提供了完整的实现代码供参考。
封装Promise

本文仅根据 Promise A+ 规范实现,与v8引擎提供的Promsie行为略有不同。案例在文章结尾。

准备状态
  1. 准备promise状态
const enum Status {
    pending = 'pending',
    fulfilled = 'fulfilled',
    rejected = 'rejected'
}
  1. promise 实例上要有 then,catch,finally 方法,promise支持连续.调用,所以这三个方法都要返回一个 promise
interface ThenAble {
    then(resFunc: (arg: any) => any, rejFunc?: (arg: any) => any): _Promise
    catch(res: (arg: any) => any): _Promise
    finally(res: (arg: any) => any): _Promise
}
  1. promise要能够进行状态流转、数据更新,但状态流转、数据更新的方法在外部不允许访问
// 抽象类 定义内部状态
abstract class __Promise {
	// 定义 status 保存状态
    protected status: Status
    // 定义 data 保存数据
    protected data: unknown
    // 定义状态流转方式
    protected abstract toResolve(arg: any): any
    protected abstract toReject(arg: any): any
    // 初始化状态,数据
    constructor() {
        this.status = Status.pending
        this.data = undefined
    }
}
  1. 创建 _Promise 类继承 __Promise 并实现 ThenAble接口
class _Promise extends __Promise implements ThenAble{
 	// ... 省去其他部分代码
 	// 首先实现toResolve 方法
    protected toResolve(arg: any) {
    	// 判断当前 Promise 状态,仅在 pending 状态下更新状态和数据
        if (this.status !== Status.pending) {
            return
        }
        this.status = Status.fulfilled
        this.data = arg
    }
    // toreject方法 同上,仅在 pending 状态下更新状态和数据
    protected toReject(arg: any) {
        if (this.status !== Status.pending) {
            return
        }
        this.status = Status.rejected
        this.data = arg
    }
	// then 方法
    then(resFunc: (arg: any) => any, rejFunc?: ((arg: any) => any)): _Promise {
    	// 保存当前 this 用于在比闭包中查看当前promise状态
        const that = this
        // 返回 promise 支持连续 . 调用
        return new _Promise((res, rej) => {
        	// 创建 thenCallback 便于之后加入 微任务队列
            const doCallback = () => {
            	// 根据 promise 状态执行不同的回调函数
                if (that.status === Status.fulfilled) {
                    if (typeof resFunc === 'function') {
                        const data = resFunc(that.data)
                        // 仅当 resFunc 显示返回一个 promise 时 then 可以返回 rejected 状态的 promise
                        if (data instanceof _Promise) {
                            data.then((d) => { res(d) }, d => { rej(d) })
                        } else {
                            res(data)
                        }
                    }
                    return
                }
            	// 根据 promise 状态执行不同的回调函数
                if (that.status === Status.rejected) {
                
                    if (typeof rejFunc === 'function') {
                        const data = rejFunc(that.data)
                        // 当传入 rejFunc 时 仅在 rejFunc 显示返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
                        if (data instanceof _Promise) {
                            data.then(d => res(d), d => rej(d))
                        } else {
                            res(data)
                        }
                    }
                    // 未传入 rejFunc 时,将当前 promise 状态、数据传递给 then 返回的 promise
                    else {
                        rej(that.data)
                    }
                    return
                }
                // promise 仍为 pending 状态 创建宏任务,将 thenCallback 再次加入到微任务队列
                setTimeout(() => { queueMicrotask(doCallback) })
            }
            queueMicrotask(doCallback)
        })
    }
    // catch 方法 和 then 方法相同思路,但只在 promise 状态为 rejected 时执行回调
    catch(catchFunc: (arg: any) => any): _Promise {
        const that = this
        return new _Promise(((res, rej) => {
            const catchCallback = () => {
            	// 仅在当前状态为 pending 时将 catchCallback 再次加入到微任务队列
                if (that.status === Status.pending) {
                    setTimeout(() => { queueMicrotask(catchCallback) })
                    return
                }
                // 当 promise 状态为 rejected 时执行回调
                if (that.status === Status.rejected) {
                    if (typeof catchFunc === 'function') {
                        const data = catchFunc(that.data)
                        // 当传入 rejFunc 时 仅在 rejFunc 显式返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
                        if (data instanceof _Promise) {
                            data.then(d => res(d), d => rej(d))
                            return
                        }
                        res(data)
                    }
                }
                res(that.data)
            }
            queueMicrotask(catchCallback)
        }))
    }
    // finally 方法 思路同上 
    finally(finallyFunc: (arg: any) => any): _Promise {
        const that = this
        return new _Promise((res, rej) => {
            const finallyCallback = () => {
                if (that.status === Status.pending) {
                    setTimeout(() => queueMicrotask(finallyCallback))
                    return
                }
                if (typeof finallyFunc === 'function') {
                    const data = finallyFunc(that.data)
                    if (data instanceof _Promise) {
                        data.then((d) => res(d), d => rej(d))
                        return
                    }
                    res(data)
                }
            }
            queueMicrotask(finallyCallback)
        })

    }
}

  1. 添加 _Promise 的静态方法
class _Promise extends __Promise implements ThenAble {

	// 省去部分代码
	
	// resolve 方法 返回一个 fulfilled 状态的 promise
    static resolve(arg: unknown): _Promise {
        return new _Promise((res) => res(arg))
    }
    // reject 方法,返回一个 rejected 状态的 Promise
    static reject(arg: unknown): _Promise {
        return new _Promise((res, rej) => rej(arg))
    }
    // race 方法 根据传入promise数组最先落定状态的promise确定返回 Promise的状态和参数
    static race(arg: _Promise[]): _Promise {
        return new _Promise((res, rej) => {
        	// 对所有传入的 promise 调用 then 方法,在 then 方法传入的回调中 更改当前 promise 的状态
            arg.forEach(item => {
                item.then(data => {
                    res(data)
                }, data => {
                    rej(data)
                }
                )
            })
        })
    }
    // all 方法 传入的promise数组全部 fulfilled之后完成,如果传入的promise数组出现rejected,返回rejected状态的promise
    static all(arg: _Promise[]): _Promise {
        const status: Status[] = []
        const data: any[] = []
        return new _Promise((res, rej) => {
            arg.forEach((item, index) => {
                status[index] = Status.pending
                item.then(d => {
                	// 记录当前 promise 的位置数据,状态
                    data[index] = d
                    status[index] = Status.fulfilled
                }, d => {
                   // 当传入的 promise 存在 rejected 状态时,直接将 race 返回的 promise 置为 rejected 状态
                    rej(d)
                })
            })
            const allCallback = () => {
            	// 轮询方式与 then 方法中类似
                if (status.some(item => item === Status.rejected)) {
                    return
                }
                if (status.every(item => {
                    return item !== Status.pending
                })) {
                    res(data)
                    return
                }

                setTimeout(() => { queueMicrotask(allCallback) })

            }
            queueMicrotask(allCallback)
        })
    }
    // allSettled 方法,返回 一个Promise当所有传入promise状态落定后完成
    static allSettled(arg: _Promise[]): _Promise {
        const data: any[] = []
        const status: Status[] = []
        arg.forEach((item, index) => {
            status[index] = Status.pending
            item.then((res) => {
                data[index] = res
                status[index] = Status.fulfilled
            }, res => {
            	// 与 all 方法不同,该方法在数组中存在 rejected 状态的 promise 时不会直接置为 rejected 而是一样记录数据状态
                data[index] = res
                status[index] = Status.rejected
            })
        })
        return new _Promise((res, rej) => {
            const allSettledCallback = () => {
                if (status.some(item => item === Status.pending)) {
                    setTimeout(() => { queueMicrotask(allSettledCallback) })
                    return
                }
                res(data.map((item, index) => {
                	// 将传入的 promise 的结果以对象数组的形式传递
                    return {
                        status: status[index],
                        value: item
                    }

                }))
            }
            queueMicrotask(allSettledCallback)
        })
    }
}

完整代码

// 准备 promise 状态
const enum Status {
    pending = 'pending',
    fulfilled = 'fulfilled',
    rejected = 'rejected'
}
// promise 对象中要有 then,catch,finally 方法
interface ThenAble {
    then(resFunc: (arg: any) => any, rejFunc?: (arg: any) => any): _Promise
    catch(res: (arg: any) => any): _Promise
    finally(res: (arg: any) => any): _Promise
}
// 抽象类 定义内部状态
abstract class __Promise {
    // 定义 status 保存状态
    protected status: Status
    // 定义 data 保存数据
    protected data: unknown
    // 定义状态流转方式
    protected abstract toResolve(arg: any): any
    protected abstract toReject(arg: any): any
    // 初始化状态,数据
    constructor() {
        this.status = Status.pending
        this.data = undefined
    }
}
// 创建 _Promise 实现 ThenAble 接口
class _Promise extends __Promise implements ThenAble {
    // Promise 状态,外部不可读取
    protected status: Status
    // Promise 数据,外部不可读取
    protected data: unknown
    // resolve 方法,返回一个 fulfilled 状态的 Promise
    static resolve(arg: unknown): _Promise {
        return new _Promise((res) => res(arg))
    }
    // reject 方法,返回一个 rejected 状态的 Promise
    static reject(arg: unknown): _Promise {
        return new _Promise((res, rej) => rej(arg))
    }
    // race 方法 根据传入promise数组最先落定状态的promise确定返回 Promise的状态和参数
    static race(arg: _Promise[]): _Promise {
        return new _Promise((res, rej) => {
            // 对所有传入的 promise 调用 then 方法,在 then 方法传入的回调中 更改当前 promise 的状态
            arg.forEach(item => {
                item.then(data => {
                    res(data)
                }, data => {
                    rej(data)
                }
                )
            })
        })
    }
    // all 方法 传入的promise数组全部 fulfilled之后完成,如果传入的promise数组出现rejected,返回rejected状态的promise
    static all(arg: _Promise[]): _Promise {
        const status: Status[] = []
        const data: any[] = []
        return new _Promise((res, rej) => {
            arg.forEach((item, index) => {
                status[index] = Status.pending
                item.then(d => {
                    // 记录当前 promise 的位置数据,状态
                    data[index] = d
                    status[index] = Status.fulfilled
                }, d => {
                    // 当传入的 promise 存在 rejected 状态时,直接将 race 返回的 promise 置为 rejected 状态
                    rej(d)
                })
            })
            const allCallback = () => {
                // 轮询方式与 then 方法中类似
                if (status.some(item => item === Status.rejected)) {
                    return
                }
                if (status.every(item => {
                    return item !== Status.pending
                })) {
                    res(data)
                    return
                }

                setTimeout(() => { queueMicrotask(allCallback) })

            }
            queueMicrotask(allCallback)
        })
    }
    // allSettled 方法,返回 一个Promise当所有传入promise状态落定后完成
    static allSettled(arg: _Promise[]): _Promise {
        const data: any[] = []
        const status: Status[] = []
        arg.forEach((item, index) => {
            status[index] = Status.pending
            item.then((res) => {
                data[index] = res
                status[index] = Status.fulfilled
            }, res => {
                // 与 all 方法不同,该方法在数组中存在 rejected 状态的 promise 时不会直接置为 rejected 而是一样记录数据状态
                data[index] = res
                status[index] = Status.rejected
            })
        })
        return new _Promise((res, rej) => {
            const allSettledCallback = () => {
                if (status.some(item => item === Status.pending)) {
                    setTimeout(() => { queueMicrotask(allSettledCallback) })
                    return
                }
                res(data.map((item, index) => {
                    // 将传入的 promise 的结果以对象数组的形式传递
                    return {
                        status: status[index],
                        value: item
                    }

                }))
            }
            queueMicrotask(allSettledCallback)
        })
    }
    
    constructor(func: (resolve: (arg: unknown) => void, reject: (arg: unknown) => void) => unknown) {
        super()
        // 传入 toResolve 和 toReject 方法,并绑定this
        typeof func === 'function' && func(this.toResolve.bind(this), this.toReject.bind(this))
    }
    // toResolve 将promise 状态转换为 fulfilled,外部不可访问
    protected toResolve(arg: any) {
        // 判断当前 Promise 状态,仅在 pending 状态下更新状态和数据
        if (this.status !== Status.pending) {
            return
        }
        this.status = Status.fulfilled
        this.data = arg
    }
    // toreject方法 同上,仅在 pending 状态下更新状态和数据
    protected toReject(arg: any) {
        if (this.status !== Status.pending) {
            return
        }
        this.status = Status.rejected
        this.data = arg
    }
    // then 方法
    then(resFunc: (arg: any) => any, rejFunc?: ((arg: any) => any)): _Promise {
        // 保存当前 this 用于在比闭包中查看当前promise状态
        const that = this
        // 返回 promise 支持连续 . 调用
        return new _Promise((res, rej) => {
            // 创建 thenCallback 便于之后加入 微任务队列
            const doCallback = () => {
                // 根据 promise 状态执行不同的回调函数
                if (that.status === Status.fulfilled) {
                    if (typeof resFunc === 'function') {
                        const data = resFunc(that.data)
                        // 仅当 resFunc 显示返回一个 promise 时 then 可以返回 rejected 状态的 promise
                        if (data instanceof _Promise) {
                            data.then((d) => { res(d) }, d => { rej(d) })
                        } else {
                            res(data)
                        }
                    }
                    return
                }
                // 根据 promise 状态执行不同的回调函数
                if (that.status === Status.rejected) {

                    if (typeof rejFunc === 'function') {
                        const data = rejFunc(that.data)
                        // 当传入 rejFunc 时 仅在 rejFunc 显示返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
                        if (data instanceof _Promise) {
                            data.then(d => res(d), d => rej(d))
                        } else {
                            res(data)
                        }
                    }
                    // 未传入 rejFunc 时,将当前 promise 状态、数据传递给 then 返回的 promise
                    else {
                        rej(that.data)
                    }
                    return
                }
                // promise 仍为 pending 状态 创建宏任务,将 thenCallback 再次加入到微任务队列
                setTimeout(() => { queueMicrotask(doCallback) })
            }
            queueMicrotask(doCallback)
        })
    }
    // catch 方法 和 then 方法相同思路,但只在 promise 状态为 rejected 时执行回调
    catch(catchFunc: (arg: any) => any): _Promise {
        const that = this
        return new _Promise(((res, rej) => {
            const catchCallback = () => {
                // 仅在当前状态为 pending 时将 catchCallback 再次加入到微任务队列
                if (that.status === Status.pending) {
                    setTimeout(() => { queueMicrotask(catchCallback) })
                    return
                }
                // 当 promise 状态为 rejected 时执行回调
                if (that.status === Status.rejected) {
                    if (typeof catchFunc === 'function') {
                        const data = catchFunc(that.data)
                        // 当传入 rejFunc 时 仅在 rejFunc 显式返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
                        if (data instanceof _Promise) {
                            data.then(d => res(d), d => rej(d))
                            return
                        }
                        res(data)
                    }
                }
                res(that.data)
            }
            queueMicrotask(catchCallback)
        }))
    }
    // finally 方法 思路同上 
    finally(finallyFunc: (arg: any) => any): _Promise {
        const that = this
        return new _Promise((res, rej) => {
            const finallyCallback = () => {
                if (that.status === Status.pending) {
                    setTimeout(() => queueMicrotask(finallyCallback))
                    return
                }
                if (typeof finallyFunc === 'function') {
                    const data = finallyFunc(that.data)
                    if (data instanceof _Promise) {
                        data.then((d) => res(d), d => rej(d))
                        return
                    }
                    res(data)
                }
            }
            queueMicrotask(finallyCallback)
        })

    }
}

未经过严密测试,如有问题请评论告诉我

注:该实现与v8引擎提供的 promise 在行为上略有差异

// const _Promise = Promise

_Promise
  .resolve(undefined)
  .then(() => {
    console.log(0);
    return _Promise.resolve(4);
  })
  .then((res) => console.log(res));

_Promise
  .resolve(undefined)
  .then((_) => {
    console.log(1);
  })
  .then((_) => {
    console.log(2);
  })
  .then((_) => {
    console.log(3);
  })
  .then((_) => {
    console.log(5);
  })
  .then((_) => {
    console.log(6);
  });
// v8 引擎下 该案例输出 0 1 2 3 4 5 6
// 本文实现下 该案例输出 0 1 2 3 5 6 4
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值