JS基于Promises/A+规范实现一个Promise

   本文基于Promises/A+实现一个Promise对象,帮助大家理解使用它。

  说明一下,Promises/A+是ES6中Promise的前身,规范可以参考:https://promisesaplus.com/

  ES6白皮书参考地址:https://tc39.es/ecma262/#sec-promise-objects

  MDN文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

  首先,根据Promises/A+规范,定义了一些术语,重要的就Promise和Thenable:  

    Promise是一个具有then方法的对象或者函数,这个then方法需要满足后面的一些规范。
    Thenable是一个具有then方法的对象或者函数。

  从上面的术语可以看到,PromiseThenable,但是Thenable不一定是Promise,主要区别有两点:

  1. Promise对象具有三个状态:pending, fulfilled, rejected  

    1、当状态是pending时,Promise的状态可以变为fulfilled或者rejected。
    2、当状态是fulfilled时,Promise的状态不可再改变,并具有一个不可改变的结果,结果可以是null、undefined、对象、函数、Promise或者Thenable等。
    3、当状态是rejected时,Promise的状态不可再改变,并可具有一个不可改变的原因,原因可以是null、undefined、对象、函数、Promise或者Thenable等。

   2. Promise对象需要提供一个then方法,这个then方法需要接收两个参数:   

    promise.then(onFulfilled, onRejected)
    
    //onFulfilled是当promise状态从pending变为fulfilled后需要执行的函数
    //onRejected是当promise状态从pending变为rejected后需要执行的函数

  而在ES6的规范中,Promise不仅满足上面Promises/A+规范,还有其他一些特性来保证Promise的实用性,比如ES6中,Promise的构造函数需要传入一个executor函数参数,它接收两个函数作为参数:resolveFunc rejectFunc,分别表示将Promise的状态置为fulfilled还是rejected,因此,我们可以写出Promise的构造函数大概是这个样子的:

    class MyPromise {
        constructor(executor) {
            //表示状态是否已指定,保证状态只会被改变一次
            let specified = false
            //状态
            let state = PENDING
            //结果或者原因
            let value = void 0

            //fulfilled状态的回调函数
            let onFulfilledCallbacks = []
            //rejected状态的回调函数
            let onRejectedCallbacks = []

            //resolve函数,改变状态为fulfilled
            const resolve = (result) => { }
            //reject函数,改变状态为rejected
            const reject = (reason) => { }

            //then方法
            this.then = (onFulfilled, onRejected) => { }

            try {
                executor(resolve, reject)
            } catch (error) {
                reject(error) //如果executor抛出异常,那么直接reject
            }
        }
    }

  上面只是Promise大致的样子,接下来我们就需要去实现这几个函数即可:resolverejectthen方法

  首先,我们需要先定义一些通用的函数与变量:  

    //Promise的三个状态
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    //判断一个值是否是一个函数
    const isFunction = value => value && typeof value === 'function' && value instanceof Function
    //判断一个值是否是一个Promise
    const isPromise = value => value && (value instanceof MyPromise || value instanceof Promise)
    //判断一个值是否是一个对象
    const isObject = value => value && typeof value === 'object' && value instanceof Object
    //执行微任务,没有返回结果
    function runMicroTask(fn) {
        //首先看微任务队列函数是否存在,如果存在则使用微任务队列执行
        if (isFunction(queueMicrotask)) {
            runMicroTask = f => queueMicrotask(f)
        } else if (isObject(process) && isFunction(process.nextTick)) { //如果是Node.js环境
            runMicroTask = f => process.nextTick(f)
        } else if (isFunction(MutationObserver)) { //如果是浏览器环境
            runMicroTask = f => {
                const observer = new MutationObserver(f)
                const node = document.createTextNode('')
                observer.observe(node, { characterData: true })
                node.data = '1' //触发MutationObserver
            }
        } else { //如果都不存在,那么使用setTimeout(fn, 0)执行
            runMicroTask = f => setTimeout(f, 0)
        }
        runMicroTask(fn)
    }

  reject函数

  reject函数的视线很简单,就是变更Promise的状态和结果即可,结果往往是一个Error对象:  

    //reject函数,改变状态为rejected
    const reject = (reason) => {
        //当且仅当状态是pending且未指定时进入
        if (state === PENDING && !specified) {
            [state, value, specified] = [REJECTED, reason, true]

            //rejected状态的回调函数,将其添加到onRejectedCallbacks数组中,判断是否执行回调函数
            runOrQueueTasks(onRejectedCallbacks, REJECTED)
        }
    }

  这里runOrQueueTasks其实就是将回调函数放到微任务里并准备执行回调函数,实现如下:  

    const runOrQueueTasks = (callbacks, requireState, callback) => {
        //如果callback是函数,那么将其添加到callbacks数组中
        callback && callbacks.push(callback)
        //如果是指定状态,那么使用微任务执行
        if (state === requireState) {
            while (callbacks.length) {
                const cb = callbacks.shift()
                runMicroTask(() => cb(value)) // 使用微任务执行
            }
        }
    }

  resolve函数

  resolve的函数实现逻辑更多一些,具体可以看看MDN的说明(跳转),总结下来就是:  

    1、resolve函数接收一个结果对象result
    2、如果result结果对象是当前Promise自身,那么将会reject一个TypeError
    3、如果result结果对象不是一个Thenable对象,那么Promise将会被立即FULFILLED,并采用这个result作为结果
    4、如果result结果对象是一个Thenable对象,那么将会把Thenable对象的then方法放到微任务去执行,并Promise的resolve和reject作为then方法的两个参数传进入(近似可以这么认为),就是说Promise的结果又Thenable决定

  因此我们的resolve函数大概是这个样子的:  

    //resolve函数,改变状态为fulfilled
    const resolve = (result) => {
        //当且仅当状态是pending且未指定时进入
        if (state === PENDING && !specified) {
            //如果传入的是当前Promise对象,那么直接reject
            if (result === this) {
                return reject(new TypeError('Chaining cycle detected for promise'))
            }
            specified = true;

            //如果result是Thenable,那么调用(ES6白皮书)
            //如果result是一个Promise,那么吸收它的状态
            try {
                if (result && isFunction(result.then)) {
                    return runMicroTask(() => {
                        try {
                            const res = r => (specified = false, resolve(r)) //临时打开
                            const rej = r => (specified = false, reject(r))  //临时打开             
                            result.then(res, rej)
                        } catch (error) {
                            reject(error)
                        }
                    })
                }
            } catch (error) {
               return reject(error) //如果result.then抛出异常,那么直接reject
            }

            [state, value] = [FULFILLED, result]

            //fulfilled状态的回调函数,将其添加到onFulfilledCallbacks数组中,判断是否执行回调函数
            runOrQueueTasks(onFulfilledCallbacks, FULFILLED)
        }
    }

  then方法 

  根据Promises/A+规范,then方法需要满足下面的:  

    1、调用方式:promise.then(onFulfilled, onRejected),这里onFulfilled、onRejected都必须是函数,否则将被忽略
    2、onFulfilled、onRejected需要分别在promise变为fulfilled和rejected后执行,将结果或者原因作为第一个参数传入,并且至多执行一次
    3、onFulfilled、onRejected不能在当前上下文中执行,需要放到setTimeout、微任务这样的上下文去执行
    4、then方法如果调用多次,onFulfilled和onRejected需要按他们所在的then方法的调用顺序依次执行
    5、then方法方法需要返回一个新的Promise对象:promise2 = promise1.then(onFulfilled, onRejected)
        1、如果onFulfilled和onRejected返回一个值x,那么将执行Promise Resolution Procedure,将promise2和x作为参数传入
        2、如果onFulfilled或者onRejected抛出异常,那么promise2将会使用这个异常进行reject
        3、如果onFulfilled不是函数且promise1状态是fulfilled,或者onRejected不是函数且promise1状态是rejected,那么promise2将会吸收promise1的状态,即promise1和promise2保持相同的结果和状态

   因为then方法的实现大致如下

    //then方法
    this.then = (onFulfilled, onRejected) => {
        const promise = new (this.constructor[Symbol.species] || MyPromise)((resolve, reject) => {
            //如果onFulfilled是函数则调用
            state !== REJECTED && runOrQueueTasks(onFulfilledCallbacks, FULFILLED, isFunction(onFulfilled) ? value => {
                try {
                    const x = onFulfilled(value)
                    //根据函数返回结果进行Promise Resolution Procedure过程
                    promiseResolutionProcedure(promise, x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } : resolve)//否则根据当前状态直接resolve

            //如果onRejected是函数则调用
            state !== FULFILLED && runOrQueueTasks(onRejectedCallbacks, REJECTED, isFunction(onRejected) ? value => {
                try {
                    const x = onRejected(value)
                    //根据函数返回结果进行Promise Resolution Procedure过程
                    promiseResolutionProcedure(promise, x, resolve, reject)
                } catch (error) {
                    reject(error)
                }
            } : reject)//否则根据当前状态直接reject
        })
        return promise
    }

   这里说下Promise Resolution Procedure过程

    Promise Resolution Procedure过程采用这个表达方式:[[Resolve]](promise, x),其实可以理解为就是个函数处理过程,表示promise怎么去根据x的值变更状态
    1、如果promise和x是相同的对象,那么promise将会被reject(TypeError)
    2、如果x是一个Promise,那么promise对象将会吸收x的状态,即promise和x保持相同的结果和状态
    3、如果x是一个Thenable,那么调用Thenable的then方法,并将promise的resolve和reject函数作为参数传入then方法调用
        1、如果resolve函数被调用,并接收到结果y,那么接着执行Promise Resolution Procedure过程:[[Resolve]](promise, y)
        2、如果reject函数被调用,那么接收到结果r,那么promise将会被reject(r)
        3、resolve和reject函数只能被调用一次
        4、如果then方法调用报错,且resolve和reject函数都未被调用,那么promise将会被reject
    4、否则promise将会被resolve(x)

  大致的实现代码是这个样子的:  

    //Promise状态处理过程
    const promiseResolutionProcedure = (promise, x, resolve, reject) => {
        // promise和x不能引用同一个对象
        if (promise === x) {
            throw new TypeError('Chaining cycle detected for promise')
        }

        //如果x是一个Promise,那么promise对象直接吸收x的状态
        if (isPromise(x)) { //这里兼容一下原生Promise
            //这里ES6白皮书是放到微队列中执行的(PromiseA+规范没有确定)
            return runMicroTask(() => x.then(resolve, reject))
        }

        //如果x是对象或者函数
        if (isObject(x) || isFunction(x)) {
            let ignoreCall = false
            try {
                //取then方法报错,那么直接reject
                let then = x.then
                //如果then是一个函数,那么调用then方法
                if (isFunction(then)) {
                    //调用采用x作为this,并传入两个参数resolve和reject,并要求resolve和reject只能调用一次 
                    return runMicroTask(() => then.call(x, y => {
                        ignoreCall = ignoreCall || !promiseResolutionProcedure(promise, y, resolve, reject)
                    }, r => {
                        ignoreCall = ignoreCall || !reject(r)
                    }))
                }
            } catch (error) {
                //如果then方法已经调用了resolve或reject,那么直接忽略
                ignoreCall || reject(error)
            }
        }
        //如果x不是一个对象或者函数,那么直接resolve
        resolve(x)
    }

   注:这里then方法的实现是参考Promises/A+规范,MDN上的描述大致含义和这个差不多,感兴趣的可以去看看跳转

  到这里我们的Promise就已经实现了,接下来说说Promise其它方法的拓展,这部分不是Promises/A+规范的内容,是ES6的Promise的拓展

  catch函数

  catch函数可以参考MDN上面的说明(跳转),而我们的实现如下:  

    class MyPromise {
        //...其它代码
        
        //以下是ES6白皮书的拓展,不是Promise A+规范的内容
        catch(onRejected) {
            return this.then(null, onRejected)
        }
    }

  finally函数

  finally函数可以参考MDN上面的说明(跳转),而我们的实现如下:

    class MyPromise {
        //...其它代码
        
        finally(onFinally) {
            //onFinally是一个不接收任何参数的函数
            //如果 onFinally 抛出错误或返回被拒绝的 promise,则新的 promise 将使用该值进行拒绝
            const onThen = isFunction(onFinally)?() => {
                const result = onFinally()
                if (isPromise(result)) {
                    return result.then(() => this, () => result)
                }
                return this;
            } : onFinally
            return this.then(onThen, onThen)
        }
    }

  resolve函数

  resolve函数可以参考MDN上面的说明(跳转),而我们的实现如下:  

    class MyPromise {
        //...其它代码
        
        static resolve(value) {
            //如果value是一个Promise,那么直接返回
            if (isPromise(value)) {
                return value
            }
            //使用call(this)用以支持非Promise构造器(ES6白皮书)
            const { promise, resolve } = MyPromise.withResolvers.call(this)
            resolve(value) //直接resolve
            return promise
        }
    }

  reject函数

  reject函数可以参考MDN上面的说明(跳转),而我们的实现如下: 

    class MyPromise {
        //...其它代码
        
        static reject(reason) {
            //使用call(this)用以支持非Promise构造器(ES6白皮书)
            const { promise, reject } = MyPromise.withResolvers.call(this)
            reject(reason) //直接reject
            return promise
        }
    }

  all函数

  all函数可以参考MDN上面的说明(跳转),而我们的实现如下: 

    class MyPromise {
        //...其它代码
        
        static all(promises) {
            promises = [...promises]
            const { promise, resolve, reject } = MyPromise.withResolvers()
            const results = []
            //如果是空数组,那么直接返回一个resolved的Promise
            if (!promises.length) {
                resolve(results)
            } else {
                promises.forEach((p, i) => {
                    MyPromise.resolve(p).then(value => {
                        results[i] = value
                        promises.pop() //每执行完成就弹出一个进行计数
                        //如果全部已经是fulfilled状态,那么resolve结果
                        promises.length || resolve(results)
                    }, reject)
                })
            }
            return promise
        }
    }

  race函数

  race函数可以参考MDN上面的说明(跳转),而我们的实现如下:

    class MyPromise {
        //...其它代码
        
        static race(promises) {
            promises = [...promises]
            const { promise, resolve, reject } = MyPromise.withResolvers()
            //只要有一个是fulfilled或者rejected,那么当前Promise就需要改变状态
            promises.forEach(p => MyPromise.resolve(p).then(resolve, reject))
            return promise
        }
    }

  allSettled函数

  allSettled函数可以参考MDN上面的说明(跳转),而我们的实现如下:

    class MyPromise {
        //...其它代码
        
        static allSettled(promises) {
            promises = [...promises]
            const { promise, resolve } = MyPromise.withResolvers()
            const results = []
            //如果是空数组,那么直接返回一个resolved的Promise
            if (!promises.length) {
                resolve(results)
            } else {
                promises.forEach((p, i) => {
                    MyPromise.resolve(p).then(value => {
                        results[i] = { status: FULFILLED, value }
                        promises.pop() //每执行完成就弹出一个进行计数
                        //全部Promise已经是fulfilled或者rejected状态了,那么resolve
                        promises.length || resolve(results)
                    }, reason => {
                        results[i] = { status: REJECTED, reason }
                        promises.pop() //每执行完成就弹出一个进行计数
                        //全部Promise已经是fulfilled或者rejected状态了,那么resolve
                        promises.length || resolve(results)
                    })
                })
            }
            return promise
        }
    }

  any函数

  any函数可以参考MDN上面的说明(跳转),而我们的实现如下:

    class MyPromise {
        //...其它代码
        
        static any(promises) {
            promises = [...promises]
            const { promise, resolve, reject } = MyPromise.withResolvers()
            const errors = []
            //如果是空数组,那么直接返回一个rejected的Promise
            if (!promises.length) {
                reject(new AggregateError(errors, 'All promises were rejected'))
            } else {
                promises.forEach((p, i) => {
                    MyPromise.resolve(p).then(resolve, reason => {
                        errors[i] = reason
                        promises.pop() //每执行完成就弹出一个进行计数
                        //如果有rejected,那么收集所有rejected并最后全局reject
                        promises.length || reject(new AggregateError(errors, 'All promises were rejected'))
                    })
                })
            }
            return promise
        }
    }

  try函数

  try函数可以参考MDN上面的说明(跳转),而我们的实现如下:  

    class MyPromise {
        //...其它代码
        
        static try(fn, ...args) {
            //使用call(this)用以支持非Promise构造器(ES6白皮书)
            const { promise, resolve, reject } = MyPromise.withResolvers.call(this)
            try {
                const result = fn(...args)
                resolve(result)
            } catch (error) {
                reject(error)
            }
            return promise
        }
    }

  withResolvers函数

  withResolvers函数可以参考MDN上面的说明(跳转),而我们的实现如下:

    class MyPromise {
        //...其它代码
        
        static withResolvers() {
            let resolve, reject
            const promise = new this((res, rej) => {
                resolve = res
                reject = rej
            })
            return { promise, resolve, reject }
        }
    }

  最后附上自己实现的Promise完整代码:

查看代码
    //Promise的三个状态
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    //判断一个值是否是一个函数
    const isFunction = value => value && typeof value === 'function' && value instanceof Function
    //判断一个值是否是一个Promise
    const isPromise = value => value && (value instanceof MyPromise || value instanceof Promise)
    //判断一个值是否是一个对象
    const isObject = value => value && typeof value === 'object' && value instanceof Object
    //执行微任务,没有返回结果
    function runMicroTask(fn) {
        //首先看微任务队列函数是否存在,如果存在则使用微任务队列执行
        if (isFunction(queueMicrotask)) {
            runMicroTask = f => queueMicrotask(f)
        } else if (isObject(process) && isFunction(process.nextTick)) { //如果是Node.js环境
            runMicroTask = f => process.nextTick(f)
        } else if (isFunction(MutationObserver)) { //如果是浏览器环境
            runMicroTask = f => {
                const observer = new MutationObserver(f)
                const node = document.createTextNode('')
                observer.observe(node, { characterData: true })
                node.data = '1' //触发MutationObserver
            }
        } else { //如果都不存在,那么使用setTimeout(fn, 0)执行
            runMicroTask = f => setTimeout(f, 0)
        }
        runMicroTask(fn)
    }

    class MyPromise {
        constructor(executor) {
            //表示状态是否已指定,保证状态只会被改变一次
            let specified = false
            //状态
            let state = PENDING
            //结果或者原因
            let value = void 0

            //fulfilled状态的回调函数
            let onFulfilledCallbacks = []
            //rejected状态的回调函数
            let onRejectedCallbacks = []

            //如果想看promise运行的状态和结果,可以使用下面的代码
            Object.defineProperty(this, 'state', { get() { return state }, configurable: false, enumerable: false })
            Object.defineProperty(this, 'value', { get() { return value }, configurable: false, enumerable: false })

            const runOrQueueTasks = (callbacks, requireState, callback) => {
                //如果callback是函数,那么将其添加到callbacks数组中
                callback && callbacks.push(callback)
                //如果是指定状态,那么使用微任务执行
                if (state === requireState) {
                    while (callbacks.length) {
                        const cb = callbacks.shift()
                        runMicroTask(() => cb(value)) // 使用微任务执行
                    }
                }
            }

            //resolve函数,改变状态为fulfilled
            const resolve = (result) => {
                //当且仅当状态是pending且未指定时进入
                if (state === PENDING && !specified) {
                    //如果传入的是当前Promise对象,那么直接reject
                    if (result === this) {
                        return reject(new TypeError('Chaining cycle detected for promise'))
                    }
                    specified = true;

                    //如果result是Thenable,那么调用(ES6白皮书)
                    //如果result是一个Promise,那么吸收它的状态
                    try {
                        if (result && isFunction(result.then)) {
                            return runMicroTask(() => {
                                try {
                                    const res = r => (specified = false, resolve(r)) //临时打开
                                    const rej = r => (specified = false, reject(r))  //临时打开                            
                                    result.then(res, rej)
                                } catch (error) {
                                    reject(error)
                                }
                            })
                        }
                    } catch (error) {
                        return reject(error) //如果result.then抛出异常,那么直接reject
                    }

                    [state, value] = [FULFILLED, result]

                    //fulfilled状态的回调函数,将其添加到onFulfilledCallbacks数组中,判断是否执行回调函数
                    runOrQueueTasks(onFulfilledCallbacks, FULFILLED)
                }
            }
            //reject函数,改变状态为rejected
            const reject = (reason) => {
                //当且仅当状态是pending且未指定时进入
                if (state === PENDING && !specified) {
                    [state, value, specified] = [REJECTED, reason, true]

                    //rejected状态的回调函数,将其添加到onRejectedCallbacks数组中,判断是否执行回调函数
                    runOrQueueTasks(onRejectedCallbacks, REJECTED)
                }
            }

            //Promise状态处理过程
            const promiseResolutionProcedure = (promise, x, resolve, reject) => {
                // promise和x不能引用同一个对象
                if (promise === x) {
                    throw new TypeError('Chaining cycle detected for promise')
                }

                //如果x是一个Promise,那么promise对象直接吸收x的状态
                if (isPromise(x)) { //这里兼容一下原生Promise
                    //这里ES6白皮书是放到微队列中执行的(PromiseA+规范没有确定)
                    return runMicroTask(() => x.then(resolve, reject))
                }

                //如果x是对象或者函数
                if (isObject(x) || isFunction(x)) {
                    let ignoreCall = false
                    try {
                        //取then方法报错,那么直接reject
                        let then = x.then
                        //如果then是一个函数,那么调用then方法
                        if (isFunction(then)) {
                            //调用采用x作为this,并传入两个参数resolve和reject,并要求resolve和reject只能调用一次 
                            return runMicroTask(() => then.call(x, y => {
                                ignoreCall = ignoreCall || !promiseResolutionProcedure(promise, y, resolve, reject)
                            }, r => {
                                ignoreCall = ignoreCall || !reject(r)
                            }))
                        }
                    } catch (error) {
                        //如果then方法已经调用了resolve或reject,那么直接忽略
                        ignoreCall || reject(error)
                    }
                }
                //如果x不是一个对象或者函数,那么直接resolve
                resolve(x)
            }

            //then方法
            this.then = (onFulfilled, onRejected) => {
                const promise = new (this.constructor[Symbol.species] || MyPromise)((resolve, reject) => {
                    //如果onFulfilled是函数则调用
                    state !== REJECTED && runOrQueueTasks(onFulfilledCallbacks, FULFILLED, isFunction(onFulfilled) ? value => {
                        try {
                            const x = onFulfilled(value)
                            //根据函数返回结果进行Promise Resolution Procedure过程
                            promiseResolutionProcedure(promise, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    } : resolve)//否则根据当前状态直接resolve

                    //如果onRejected是函数则调用
                    state !== FULFILLED && runOrQueueTasks(onRejectedCallbacks, REJECTED, isFunction(onRejected) ? value => {
                        try {
                            const x = onRejected(value)
                            //根据函数返回结果进行Promise Resolution Procedure过程
                            promiseResolutionProcedure(promise, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    } : reject)//否则根据当前状态直接reject
                })
                return promise
            }

            try {
                executor(resolve, reject)
            } catch (error) {
                reject(error) //如果executor抛出异常,那么直接reject
            }
        }

        //以下是ES6白皮书的拓展,不是Promise A+规范的内容
        catch(onRejected) {
            return this.then(null, onRejected)
        }
        finally(onFinally) {
            //onFinally是一个不接收任何参数的函数
            //如果 onFinally 抛出错误或返回被拒绝的 promise,则新的 promise 将使用该值进行拒绝
            const onThen = isFunction(onFinally) ? () => {
                const result = onFinally()
                if (isPromise(result)) {
                    return result.then(() => this, () => result)
                }
                return this;
            } : onFinally
            return this.then(onThen, onThen)
        }
        static resolve(value) {
            //如果value是一个Promise,那么直接返回
            if (isPromise(value)) {
                return value
            }
            //使用call(this)用以支持非Promise构造器(ES6白皮书)
            const { promise, resolve } = MyPromise.withResolvers.call(this)
            resolve(value) //直接resolve
            return promise
        }
        static reject(reason) {
            //使用call(this)用以支持非Promise构造器(ES6白皮书)
            const { promise, reject } = MyPromise.withResolvers.call(this)
            reject(reason) //直接reject
            return promise
        }
        static all(promises) {
            promises = [...promises]
            const { promise, resolve, reject } = MyPromise.withResolvers()
            const results = []
            //如果是空数组,那么直接返回一个resolved的Promise
            if (!promises.length) {
                resolve(results)
            } else {
                promises.forEach((p, i) => {
                    MyPromise.resolve(p).then(value => {
                        results[i] = value
                        promises.pop() //每执行完成就弹出一个进行计数
                        //如果全部已经是fulfilled状态,那么resolve结果
                        promises.length || resolve(results)
                    }, reject)
                })
            }
            return promise
        }
        static race(promises) {
            promises = [...promises]
            const { promise, resolve, reject } = MyPromise.withResolvers()
            //只要有一个是fulfilled或者rejected,那么当前Promise就需要改变状态
            promises.forEach(p => MyPromise.resolve(p).then(resolve, reject))
            return promise
        }
        static allSettled(promises) {
            promises = [...promises]
            const { promise, resolve } = MyPromise.withResolvers()
            const results = []
            //如果是空数组,那么直接返回一个resolved的Promise
            if (!promises.length) {
                resolve(results)
            } else {
                promises.forEach((p, i) => {
                    MyPromise.resolve(p).then(value => {
                        results[i] = { status: FULFILLED, value }
                        promises.pop() //每执行完成就弹出一个进行计数
                        //全部Promise已经是fulfilled或者rejected状态了,那么resolve
                        promises.length || resolve(results)
                    }, reason => {
                        results[i] = { status: REJECTED, reason }
                        promises.pop() //每执行完成就弹出一个进行计数
                        //全部Promise已经是fulfilled或者rejected状态了,那么resolve
                        promises.length || resolve(results)
                    })
                })
            }
            return promise
        }
        static any(promises) {
            promises = [...promises]
            const { promise, resolve, reject } = MyPromise.withResolvers()
            const errors = []
            //如果是空数组,那么直接返回一个rejected的Promise
            if (!promises.length) {
                reject(new AggregateError(errors, 'All promises were rejected'))
            } else {
                promises.forEach((p, i) => {
                    MyPromise.resolve(p).then(resolve, reason => {
                        errors[i] = reason
                        promises.pop() //每执行完成就弹出一个进行计数
                        //如果有rejected,那么收集所有rejected并最后全局reject
                        promises.length || reject(new AggregateError(errors, 'All promises were rejected'))
                    })
                })
            }
            return promise
        }
        static try(fn, ...args) {
            //使用call(this)用以支持非Promise构造器(ES6白皮书)
            const { promise, resolve, reject } = MyPromise.withResolvers.call(this)
            try {
                const result = fn(...args)
                resolve(result)
            } catch (error) {
                reject(error)
            }
            return promise
        }
        static withResolvers() {
            let resolve, reject
            const promise = new this((res, rej) => {
                resolve = res
                reject = rej
            })
            return { promise, resolve, reject }
        }

        static get [Symbol.species]() {
            return MyPromise
        }
        [Symbol.toStringTag]() {
            return "MyPromise"
        }
    }

  验证

   我们主要在浏览器环境下验证,我们可以尝试几个例子,把Promise换成我们自定义的MyPromise,结果是一样的:

  例子一

    Promise.resolve()
        .then(() => {
            console.log(0)
            return Promise.resolve(4)
        })
        .then(res => {
            console.log(res)
        })
    Promise.resolve()
        .then(() => {
            console.log(1);
        })
        .then(() => {
            console.log(2);
        })
        .then(() => {
            console.log(3);
        })
        .then(() => {
            console.log(5);
        })
        .then(() => {
            console.log(6);
        })

  例子二

    new Promise(function(resolve, reject) {
      console.log(1);
      resolve();
      console.log(2);
    }).then(function() {
      console.log(4);
    });
    setTimeout(()=>console.log(5))
    console.log(3);

  例子三

    const first = () => (new Promise((resolve, reject) => {
        console.log(1);
        let p = new Promise((resolve, reject) => {
            console.log(2);
            setTimeout(() => {
                console.log(6);
                resolve(7);
            }, 0)
            resolve(4);
        })
        resolve(5);
        p.then((arg) => {
            console.log(arg);
        });

    }));

    first().then((arg) => {
        console.log(arg);
    });
    console.log(3);

  总结

  以上实现是个人总结,模拟Promise的实现过程,基于ES6的实现,如果有什么错误,欢迎指出!

 

posted @ 2025-07-06 16:56  没有星星的夏季  阅读(52)  评论(0)    收藏  举报