51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

[JavaScript] 手写实现Promise

可能还存在不完善的地方,有空再改改

const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
//工具函数,捕获错误并转换为reject方法
const resolveOrCatchWithReject = (fn, val, resolve, reject) => {
    try {
        let value = fn(val)
        resolve(value)
    } catch (err) {
        reject(err)
    }
}
function isKanoPromise(x) { // 校验是否是 promise 
    if ((typeof x == 'object' && x !== null) || typeof x == 'function') {
        if (typeof x.then == 'function') {
            return true
        }
    }
    return false
}
class KanoPromise {
    constructor(executor) {
        this.status = PROMISE_STATUS_PENDING
        this.value = undefined
        this.resaon = undefined
        this.onfulfilledFns = []
        this.onrejectedFns = []
        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
                    // 执行then传入的回调函数(第一个)
                    // console.log('resolve被调用');
                    this.onfulfilledFns.forEach(fn => {
                        // if(isKanoPromise(value)){
                        //     value.then(res=>{
                        //         return res
                        //     })
                        // }
                        fn && fn(this.value)
                    })
                })
            }
        }
        const reject = (resaon) => {
            if (this.status === PROMISE_STATUS_PENDING) {
                queueMicrotask(() => { //微任务队列
                    if (this.status !== PROMISE_STATUS_PENDING) return
                    this.status = PROMISE_STATUS_REJECTED
                    this.resaon = resaon
                    // 执行then传入的回调函数(第二个)
                    // console.log('reject被调用');
                    this.onrejectedFns.forEach(fn => {
                        fn && fn(this.resaon)
                    })
                });
            }
        }

        try {
            executor(resolve, reject)
        } catch (err) {
            reject(err)
        }
    }

    then(onfulfilled, onrejected) {
        //兼容catch托底方法(当then没有onrejected时)
        const defaultOnRejected = errOrData => { throw errOrData }
        onrejected = onrejected || defaultOnRejected
        //没有onfulfilled时需要有一个默认的onfulfilled
        const defaultOnFulfilled = value => { return value }
        onfulfilled = onfulfilled || defaultOnFulfilled

        //返回一个promise 实现then的链式调用
        return new KanoPromise((resolve, reject) => {
            //状态已敲定,不入队列,直接执行
            if (this.status === PROMISE_STATUS_FULFILLED) {
                resolveOrCatchWithReject(onfulfilled, this.value, resolve, reject)
            }
            //状态已敲定,不入队列,直接执行
            if (this.status === PROMISE_STATUS_REJECTED) {
                resolveOrCatchWithReject(onrejected, this.resaon, resolve, reject)
            }
            //状态未敲定,将回调置入回调执行队列中
            if (this.status === PROMISE_STATUS_PENDING) {
                //置入数组
                this.onfulfilledFns.push(() => {
                    resolveOrCatchWithReject(onfulfilled, this.value, resolve, reject)
                })
                this.onrejectedFns.push(() => {
                    resolveOrCatchWithReject(onrejected, this.resaon, resolve, reject)
                })
            }
        })
    }

    catch(onrejected) {
        //执行then,reject动作由catch方法的onrejected回调函数托管
        return this.then(undefined, onrejected)
    }

    finally(onfinally) {
        //不管成功还是失败,都执行
        return this.then(onfinally, onfinally)
    }

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

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

    static all(promises) {
        return new KanoPromise((resolve, reject) => {
            const vals = []
            promises.forEach(p => {
                p.then(res => {
                    vals.push(res)
                    if (vals.length === promises.length) {
                        resolve(vals)
                    }
                }, err => {
                    reject(err)
                })
            })
        })
    }

    static allSettled(promises) {
        return new KanoPromise((resolve) => {
            const vals = []
            promises.forEach(p => {
                p.then(res => {
                    vals.push({ status: PROMISE_STATUS_FULFILLED, value: res })
                    if (vals.length === promises.length) {
                        resolve(vals)
                    }
                }, err => {
                    vals.push({ status: PROMISE_STATUS_REJECTED, reason: err })
                    if (vals.length === promises.length) {
                        resolve(vals)
                    }
                })
            })
        })
    }
    static race(promises) {
        return new KanoPromise((resolve, reject) => {
            promises.forEach(p => {
                if (isKanoPromise(p)) {
                    p.then((res) => resolve(res), reject)
                } else {
                    resolve(p)
                }
            })
        })
    }

    static any(promises) {
        const reasons = []
        return new KanoPromise((resolve, reject) => {
            promises.forEach(p => {
                p.then(resolve, err => {
                    reasons.push(err)
                    if (reasons.length === promises.length) {
                        reject(new AggregateError(reasons))
                    }
                })
            })
        })
    }



`}`

赞(0)
未经允许不得转载:工具盒子 » [JavaScript] 手写实现Promise