手写promise,已通过Promise A+规范测试

已通过Promise A+规范测试,仅用于学习,加深理解Promise

console.log("================promise================")

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECT = 'rejected'

/**
 * 异步任务-函数封装
 * 1、定义函数
 * 2、调用核心异步方法,(queueMicrotask, MutationObserver, setTimeout)
 * 
 * @param {*} callback 回调函数
 */
function runAsynctask(callback) {
    // 2、调用核心异步方法,(queueMicrotask, MutationObserver, setTimeout)
    // 兼容性判断
    if (typeof queueMicrotask === 'function') {
        queueMicrotask(callback)
    } else if (typeof MutationObserver === 'function') {
        const obs = new MutationObserver(callback)
        const divNode = document.createElement('div')
        obs.observe(divNode, { childList: true })
        divNode.innerText = 'Promise 666'
    } else {
        // 使用setTimeout 兜底
        setTimeout(callback, 0)
    }

}

class MyPromise {

    PromiseState = PENDING
    PromiseResult = void 0
    onFulfilledCallBack = []
    onRejectedCallBack = []

    constructor(executor) {

        const resolve = (data) => {
            if (this.PromiseState !== PENDING) return
            this.PromiseState = FULFILLED
            this.PromiseResult = data
            // 调用成功的回调
            this.onFulfilledCallBack.forEach(onFulfilled => {
                onFulfilled(data)
            })
        }

        const reject = (reason) => {
            if (this.PromiseState !== PENDING) return
            this.PromiseState = REJECT
            this.PromiseResult = reason
            // 调用失败的回调
            this.onRejectedCallBack.forEach(onRejected => {
                onRejected(reason)
            })
        }

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

    // promise 规范  解决过程 
    // 1、如果x不是对象或函数,则直接用x作为值来实现Promise。
    then(onFulFilled, onRejected) {
        // 1、如果x不是对象或函数,则直接用x作为值来实现Promise。
        onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : x => x
        onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
        // 链式调用返回一个promise
        const p2 = new MyPromise((resolve, reject) => {
            // 如果成功执行成功 ,如果失败执行失败
            if (this.PromiseState === FULFILLED) {
                // 使用封装的异步方法包裹
                runAsynctask(() => {
                    try {
                        // 获取到返回值 调用resolve方法 触发链式调用的then方法的第一个回调
                        const res = onFulFilled(this.PromiseResult)
                        // 4、调用函数
                        resolvePromise(p2, res, resolve, reject)
                        // 1、处理重复引用
                        // if (res === p2) {
                        //     throw new TypeError('Chaining cycle detected for promise #<Promise>')
                        // }
                        // if (res instanceof MyPromise) {
                        //     res.then(res => resolve(res), error => reject(error))
                        // } else {
                        //     resolve(res)
                        // }
                    } catch (error) {
                        reject(error)
                    }
                })
            } else if (this.PromiseState === REJECT) {
                // 使用封装的异步方法包裹
                runAsynctask(() => {
                    try {
                        // 2、获取到返回值 调用resolve方法 触发链式调用的then方法的第二个回调
                        const res = onRejected(this.PromiseResult)
                        // 4、调用函数
                        resolvePromise(p2, res, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                })
            } else if (this.PromiseState === PENDING) {
                // 如果都不是说明是一个异步操作
                // 使用封装的异步方法包裹
                this.onFulfilledCallBack.push(() => {
                    runAsynctask(() => {
                        // 1、处理异常
                        try {
                            const res = onFulFilled(this.PromiseResult)
                            resolvePromise(p2, res, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
                this.onRejectedCallBack.push(() => {
                    runAsynctask(() => {
                        // 1、处理异常
                        try {
                            const res = onRejected(this.PromiseResult)
                            resolvePromise(p2, res, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
            }
        })
        return p2
    }

    catch(onRejected) {
        return this.then(undefined, onRejected)
    }

    finally(onFinally) {
        return this.then(onFinally, onFinally)

    }
    // 传入如果是promise 就直接返回,如果不是就返回成功的promise
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        }
        return new MyPromise((resolve, reject) => {
            resolve(value)
        })
    }

    static reject(value) {
        return new MyPromise((undefined, reject) => {
            reject(value)
        })
    }

    static race(promises) {
        return new MyPromise((resolve, reject) => {
            // 判断传入的是不是数组
            if (!Array.isArray(promises)) {
                return reject(new TypeError('Argument is not iterable'))
            }
            // 3、等待第一个promise 敲定
            promises.forEach(p => {
                MyPromise.resolve(p).then(res => {
                    resolve(res)
                }, error => {
                    reject(error)
                })
            })
        })

    }

    /**
     * 静态方法-all
     * 1、返回promise实例
     * 2、判断是否为数组 错误信息: Argument is not iterable
     * 3、如果是空数组直接兑现
     * 4、如果全部成功就全部兑现 返回数组
     *    4.1、记录结果   使用索引来记录 保证顺序性
     *    4.2、判断全部兑现
     * 5、如果有拒绝处理第一个拒绝
     * @param {*} promises 
     * @returns 
     */
    static all(promises) {
        return new MyPromise((resolve, reject) => {
            // 2、判断是否为数组
            if (!Array.isArray(promises)) {
                return reject(new TypeError('Argument is not iterable'))
            }
            // 3、空数组直接兑现
            promises.length === 0 && resolve(promises)
            // 4、如果全部成功就全部兑现 返回数组
            let count = 0
            let result = []
            promises.forEach((p, index) => {
                MyPromise.resolve(p).then(res => {
                    result[index] = res
                    count++
                    // 4.2、全部兑现
                    count === promises.length && resolve(result)
                }, err => {
                    // 5、处理第一个拒绝
                    reject(err)
                })
            });
        })

    }

    static allSettled(promises) {
        return new MyPromise((resolve, reject) => {
            // 2、判断是否为数组
            if (!Array.isArray(promises)) {
                return reject(new TypeError('Argument is not iterable'))
            }
            // 3、空数组直接兑现
            promises.length === 0 && resolve(promises)
            let count = 0
            let result = []
            promises.forEach((p, index) => {
                MyPromise.resolve(p).then(res => {
                    result[index] = { status: FULFILLED, value: res }
                    count++
                    count === promises.length && resolve(result)
                }, err => {
                    result[index] = { status: REJECT, reason: err }
                    count++
                    count === promises.length && resolve(result)
                })
            })
        })
    }

    /**
     * 等待第一个成功或者全部都拒绝,全部都拒绝返回一个报错,进catch
     * @param {*} promises 
     */
    static any(promises) {

        return new MyPromise((resolve, reject) => {
            // 2、判断是否为数组
            if (!Array.isArray(promises)) {
                return reject(new TypeError('Argument is not iterable'))
            }

            // 3、空数组直接兑现
            promises.length === 0 && reject(new AggregateError(promises, 'All promise were rejected'))

            let count = 0
            let errors = []
            // 4、第一个兑现
            promises.forEach((p, index) => {
                MyPromise.resolve(p).then(res => {
                    resolve(res)
                }, err => {
                    errors[index] = err
                    count++
                    count === promises.length && reject(new AggregateError(errors, 'All promise were rejected'))
                })
            })
        })
    }
}

// 1、 抽取函数  
// function resolvePromise(p2, res, resolve, reject) {
//     // 1、处理重复引用
//     if (res === p2) {
//         throw new TypeError('Chaining cycle detected for promise #<Promise>')
//     }
//     if (res instanceof MyPromise) {
//         res.then(res => resolve(res), error => reject(error))
//     } else {
//         resolve(res)
//     }
// }

// 符合promise / A+ 规范(考虑了各种情况)
function resolvePromise(p2, x, resolve, reject) {
    // 2.3.3.1 如果p2和x引用同一个对象,通过typeError作为原因来拒绝promisse
    if (x === p2) {
        throw new TypeError('Chaining cycle detected for promise')
    }
    /**
     * 2.3.3.2 如果x是一个promise,采用他的状态
     * 2.3.3.3.1 如果x是pending状态,promise必须保持等待状态,直到x被fulfilled或rejected
     * 2.3.3.3.2 如果x是fuifilled状态,用相同的原因解决promise
     * 2.3.3.3.3 如果x是rejected状态,用相同的原因拒绝promise
     */
    if (x instanceof MyPromise) {
        x.then(y => {
            resolvePromise(p2, y, resolve, reject)
        }, reject)
    }
    // 2.3.3 如果x 是一个对象或者函数
    else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        // 2.3.3.1 让then成为x.then
        try {
            var then = x.then;
        } catch (e) {
            // 2.3.3.2 如果检索属性x.then 抛出了异常e,用e作为原因拒绝promise
            return reject(e)
        }

        /**
         * 2.3.3.3 如果then是一个函数,通过call调用他,并且将x作为他的this(参数1)
         * 调用then时传入两个回调函数:
         *      第一个参数叫做resolvePromsie(对应到参数2)
         *      第二个参数叫做rejectPromise(对应到参数3)
         */
        if (typeof then === 'function') {
            // 2.3.3.3.3 如果resolvePromise  和rejectPromise 均被调用,
            // 或者同一参数被调用了多次,
            // 只采用第一次调用,后续的调用会被忽略
            let called = false
            try {
                then.call(
                    x,
                    // 2.3.3.3.1 如果resolvePromise 以 成功原因 y 作为参数被调用,继续执行resolvePromise
                    y => {
                        if (called) return
                        called = true
                        resolvePromise(p2, y, resolve, reject)
                    },
                    // 2.3.3.3.2 如果rejectPromise 以拒绝原因 r 为参数被调用,继续执行resolvePromise
                    r => {
                        if (called) return
                        called = true
                        reject(r)
                    })
            }
            catch (e) {
                if (called) return
                called = true

                reject(e)
            }
        } else {
            resolve(x)
        }
    } else {
        return resolve(x)
    }


}

let aaa = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        reject(124124)
    }, 1000);
})

let bbb = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        reject(12412412)
    }, 500);
})

let ccc = MyPromise.reject(2)

const p = MyPromise.any([aaa, bbb, ccc])
p.then(res => {
    console.log('then', res)
}).catch(error => {
    console.dir(error)
})

module.exports = {
    deferred() {
        const res = {}
        res.promise = new MyPromise((resolve, reject) => {
            res.resolve = resolve
            res.reject = reject
        })
        return res
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值