手写Promise及其知识点

94 阅读3分钟

满足Promise A+规范的Promise

Promise的A+规范的重点就是then方法, 只要是一个对象有then方法, 就满足PromiseA+规范

ES6的Promise

比PromiseA+规范, 多了一些方法, 比如catch, resolve, finally, reject...

注意点:

  • 当Promise内部, 抛出一个错误的时候, 会直接去调用reject方法, 如果这个错误是异步抛出的, Promise不能捕捉到这个错误, 状态依然会是pending
  • Promise.then这个方法, 是Promise对象的灵魂, then这个方法需要放在微任务队列中, 所以就有了不同环境下的处理办法, 在node环境下, 会使用nextTick去, 如果是浏览器环境, 就去使用MutationObserver, 如果都不行, 就会使用setTimeout方法
// 定义状态
const pending = "pending"
const fulfilled = "fulfilled"
const rejected = "rejected"


class MyPromise {
    #state = pending
    #result = undefined
    #handlers = []

    constructor(execute) {
        const resolve = (data) => {
            this.#changeState(fulfilled, data)
        }
        const reject = (err) => {
            this.#changeState(rejected, err)
        }

        // 如果执行期间报错, 我就帮你去改变状态
        // 注意: 这个不能捕获异步的错误
        try {
            execute(resolve, reject)
        } catch (error) {
            reject(error)
        }

    }

    #changeState(state, res) {
        if (this.#state !== pending) return
        this.#state = state
        this.#result = res
        // console.log(this.#state, this.#result);

        this.#run()
    }

    #isPromiseLike(value) {
        if(value != null && (typeof value === 'function' || typeof value === 'object')) {
            return typeof value.then === 'function'
        } else {
            return false
        }
    }

    // 微任务队列中, then的回调是需要 放到微任务队列中去
    #runMicroTask(fn) {
        // 如果是node环境
        if(typeof process === 'object' && typeof process.nextTick === 'function') {
            process.nextTick(fn)
        }
        // 如果是浏览器环境
        else if(typeof MutationObserver === 'function') {
            const ob = new MutationObserver(fn)
            const textNode = document.createTextNode('1')
            ob.observe(textNode, {
                characterData: true
            })
            textNode.data = '2'
        }
        else {
            setTimeout(fn, 0)
        }
    }

    #runOne(callback, resolve, reject) {
        this.#runMicroTask(() => {
            if(typeof callback !== 'function') {
                // 去值穿透
                const settled = this.#state === fulfilled ? resolve : reject
                settled(this.#result)
                return
            }
            try {
                const data = callback(this.#result)
                if(this.#isPromiseLike(data)) {
                    data.then(resolve, reject)
                } else {
                    resolve(data)
                }
                
            } catch (error) {
                reject(error)
            }
        })
    }

    #run() {
        // then解决的第一个问题, 什么时候去运行回调
        if(this.#state === pending) return
        // 挨个从数组中拿到, 进行处理
        while(this.#handlers.length) {
            const { onFullfilled, onRejected, resolve, reject } = this.#handlers.shift()
            if (this.#state === fulfilled) {
                this.#runOne(onFullfilled, resolve, reject)
            } else if (this.#state === rejected) {
                this.#runOne(onRejected, resolve, reject)
            }
        }

    }

    // onFullfilled: 成功的时候, 的回调
    // onRejected: 失败的时候, 的回调

    // then只需要, 解决两件事, 
    // 1.啥时候运行传入的回调, 
    // 2.返回promise, 这个promise什么时候完成, 什么时候失败
    //  ---- 1.then返回的promise, then的参数, 不是一个回调函数, 是一个普通的值
    //        值穿透: then之前的promise是成功, then返回的promise就是成功, 反之同理
    //  ---- 2.then的参数, 是回调函数,  利用trycatch去执行, 成功就resolve结果, 失败就reject
    //  ---- 3. 回调函数的返回结果, 是一个promise, 去判断是否是promise
    then(onFullfilled, onRejected) {
        return new Promise((resolve, reject) => {
            // 在handler中记录, 这四个函数
            this.#handlers.push({
                onFullfilled,
                onRejected,
                resolve,
                reject
            });

            this.#run();
        })
    }

    // ES6的promise出现的方法
    catch(onRejected) {
        return this.then(undefined, onRejected)
    }

    // 无论成功还是失败都执行
    finally(onFinally) {
        return this.then(data => {
            onFinally()
            return data
        }, err => {
            onFinally()
            throw err
        })
    }

    static resolve(value) {
        // 如果值是一个promise, 直接返回他
        /* 
            官方解释
            如果该值本身就是一个 Promise,那么该 Promise 将被返回;
            如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数;
            否则,返回的 Promise 将会以该值兑现。
        */
        if(value instanceof MyPromise) return value
        
        let _resolve,_reject;
        const p = new MyPromise((resolve, reject) => {
            _resolve = resolve
            _reject = reject
        })
        // 如果满足promiseA+规范, 有then方法
        if(p.#isPromiseLike(value)) {
            value.then(_resolve, _reject)
        }
        // 如果是一个普通的值, 普通的对象
        else {
            _resolve(value)
        }
        return p
    }

    // 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。
    static reject(error) {
        return new MyPromise((resolve, reject) => {
            reject(error)
        })
    }
}


以上知识来自www.douyin.com/user/MS4wLj…