Promise原理还不懂?看这篇就够了(一)

212 阅读3分钟

前言

本人学习promise原理时,百度了不少相关文章,看的云里雾的。最终决定去PromiseA+的官网看规范,思考一番发现其实并没有那么绕。希望本篇能帮到你更好的理解promise的实现。

Promise规范

按照 PromiseA+ 规范来实现,手写Promise也没那么难。

重点规范(很重要)

  1. promise三种状态

    1. pending:等待状态,可以转为fulfilled或rejected。
    2. fulfilled:成功状态,不能再转为其他状态,且必须有一个返回值,返回值不能被修改。
    3. rejected:失败状态,不能再转为其他状态,且必须有一个失败原因,失败原因不能修改。
  2. then方法

    1. then有两个回调如入参,onFulfilled,onRejected,且两个回调必须为函数,否则忽略。

      1. onFulfilled必须在promise状态为fulfilled后调用,且只能调用一次。
      2. onRejected必须在promise状态为rejecte后调用,且只能调用一次。
    2. then方法的返回值必须是一个新的promise

    3. then方法可以被调用多次

    4. promise的结果一定不是promise

编码实现(这里只考虑fulfilled状态的实现)

定义基本的骨架

 (function (global) {
        const PENDING = 'pending'
        const FULFILLED = 'fulfilled'
        const REJECTED = 'rejected'

        const queueMicrotask = global.queueMicrotask || (task => setTimeout(task))

        function resolve(value) {

        }

        function reject(reason) {

        }

        class Promise {
            state = PENDING
            result = undefined
            reason = undefined
            onSuccesss = []
            onFail = []
            constructor(executor) {
                if (typeof executor === "function") {
                    executor(resolve.bind(this), reject.bind(this))
                } else {
                    throw new Error('executor must be function!!!')
                }
            }
            then(onFulfilled, onRejected) {

            }
        }
        global.MyPromise = Promise
    })(window)

实现resolve方法

根据规范,promise的结果一定不为promise,所以这里要判断情况

function resolve(value) {
    if (value instanceof Promise) {
        value.then(result => {
            this.state = FULFILLED
            this.result = result
            while (this.onSuccesss.length) {
                this.onSuccesss.shift()(this.result)
            }
        })
    } else {
        this.state = FULFILLED
        this.result = value
        while (this.onSuccesss.length) {
            this.onSuccesss.shift()(this.result)
        }
    }
}

重构一下resolve方法,提取重复代码

function resolve(value) {
    const task = result => {
        this.state = FULFILLED
        this.result = result
        while (this.onSuccesss.length) {
            this.onSuccesss.shift()(this.result)
        }
    }
    value instanceof Promise ? value.then(task) : task(value)
}

实现then方法

  1. then方法的onFulfilled回调存在两个情况被调用,状态为fulfilled时可以直接调用,pending时要存起来,在resolve中调用。
  2. onFulfilled,onRejected如果不为函数则忽略

先处理fulfilled状态的情况

then(onFulfilled, onRejected) {
    const { state, result } = this
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : v => v

    if (state === FULFILLED) {
        const data = onFulfilled(result)
        return new Promise(resolve => resolve(data))
    } else if (state === PENDING) {

    }
}

再处理状态为pending的情况,这里要注意onFulfilled并不是立马调用,而是要在状态转为fulfilled后调用,所以封为函数,先存在onSuccesss中

then(onFulfilled, onRejected) {
    const { state, result } = this
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : v => v

    if (state === FULFILLED) {
        const data = onFulfilled(result)
        return new Promise(resolve => resolve(data))
    } else if (state === PENDING) {
        return new Promise(resolve => {
            this.onSuccesss.push(res => {
                const data = onFulfilled(res)
                resolve(data)
            })
        })
    }
}

最后放入微任务队列中,简化一下代码

then(onFulfilled, onRejected) {
    const { state, result } = this
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
    onRejected = typeof onRejected === 'function' ? onRejected : v => v
    if (state === FULFILLED) {
        return new Promise(resolve => queueMicrotask(() => resolve(onFulfilled(result))))
    } else if (state === PENDING) {
        return new Promise(resolve => this.onSuccesss.push(res => queueMicrotask(() => resolve(onFulfilled(res)))))
    }
}

最终代码

(function (global) {
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    const queueMicrotask = global.queueMicrotask || (task => setTimeout(task))
    function resolve(value) {
        const task = result => {
            this.state = FULFILLED
            this.result = result
            while (this.onSuccesss.length) {
                this.onSuccesss.shift()(this.result)
            }
        }
        value instanceof Promise ? value.then(task) : task(value)
    }
    function reject(reason) { }

    class Promise {
        state = PENDING
        result = undefined
        reason = undefined
        onSuccesss = []
        onFails = null
        constructor(executor) {
            if (typeof executor === "function") {
                executor(resolve.bind(this), reject.bind(this))
            } else {
                throw new Error('executor must be function!!!')
            }
        }
        then(onFulfilled, onRejected) {
            const { state, result } = this
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
            onRejected = typeof onRejected === 'function' ? onRejected : v => v
            if (state === FULFILLED) {
                return new Promise(resolve => queueMicrotask(() => resolve(onFulfilled(result))))
            } else if (state === PENDING) {
                return new Promise(resolve => this.onSuccesss.push(res => queueMicrotask(() => resolve(onFulfilled(res)))))
            }
        }
        static resolve(value) {
            return new Promise(resolve => resolve(value))
        }
    }
    global.MyPromise = Promise
})(window)