一天一题:手写实现一个Promise

221 阅读2分钟
class Promise {
    constructor(executor) {
        this.status = 'pending' // 初始化状态
        this.value = undefined // 初始化成功返回的值
        this.reason = undefined // 初始化失败返回的原因

        // 解决处理异步的resolve
        this.onResolvedCallbacks = [] // 存放所有成功的resolve
        this.onRejectedCallbacks = [] // 存放所有失败的reject

        /**
         * @param {*} value 成功返回值
         * 定义resolve方法
         * 注意:状态只能从pending->fulfilled和pending->rejected两个
         */
        const resolve = (value) => { 
            if(this.status === 'pending') {
                this.status = 'fulfilled' // 成功时将状态转换为成功态fulfilled
                this.value = value // 将成功返回的值赋值给promise
                // 为了解决异步resolve以及返回多层promise
                this.onResolvedCallbacks.forEach(fn => {
                    fn() // 当状态变为成功态依次执行所有的resolve函数
                })
            }
        }
        const reject = (reason) => {
            if(this.status === 'pending') {
                this.status = 'rejected' // 失败时将状态转换为成功态失败态rejected
                this.reason = reason // 将失败返回的原因赋值给promise
                this.onRejectedCallbacks.forEach(fn => {
                    fn() // 当状态变为失败态依次执行所有的reject函数
                })
            }
        }
        executor(resolve, reject) // 执行promise传的回调函数
    }
    /**
     * 定义promise的then方法 
     * @param {*} onFulfilled 成功的回调
     * @param {*} onRejected 失败的回调
     */
    then(onFulfilled, onRejected) {
        // 为了解决then方法返回Promise的情况
        const promise2 = new Promise((resolve, reject) => {
            if(this.status === 'fulfilled') { // 如果状态为fulfilled时则将值传给这个成功的回调
                setTimeout(() => {
                    const x = onFulfilled(this.value) // x的值有可能为 promise || 123 || '123'...
                    // 注意:此时调用promise2时还没有返回值,要用setTimeout模拟进入第二次事件循环;先有鸡先有蛋
                    resolvePromise(promise2, x, resolve, reject) 
                }, 0)
            }
            if(this.status === 'rejected') {
                setTimeout(() => {
                    const x = onRejected(this.reason) // 如果状态为rejected时则将视频的原因传给失败的回调
                    resolvePromise(promise2, x, resolve, reject) 
                }, 0)
            }
            if(this.status === 'pending') { // 记录-》解决异步
                this.onResolvedCallbacks.push(() => {
                    setTimeout(() => {
                        const x = onFulfilled(this.value)
                        resolvePromise(promise2, x, resolve, reject) 
                    }, 0)
                })
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        const x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject) 
                    }, 0)
                })
            }
        })
        return promise2; // 解决多次链式调用的问题
    }
}

const resolvePromise = (promise2, x, resolve, reject) => {
    // console.log(promise2, x, resolve, reject)
    if(promise2 === x) { // 如果返回的值与then方法返回的值相同时
        throw TypeError('循环引用')
    }
    // 判断x是不是promise;注意:null的typeof也是object要排除
    if(typeof x === 'function' || (typeof x === 'object' && x !== null)) {
        try {
            const then = x.then // 获取返回值x上的then方法;注意方法会报错要捕获异常;原因111
            if(typeof then === 'function') { // 就认为是promise
                then.call(x, y => {
                    // resolve(y)
                    // 递归解析 ; 有可能返回多个嵌套的promise
                    resolvePromise(promise2, y, resolve, reject)
                }, r => {
                    reject(r)
                })
            }
        } catch(e) {
            reject(e)
        }
    } else {
        resolve(x);
    }
}
module.exports = Promise;