JavaScript 手动实现 Promise 核心逻辑详解

作者:半夏时间:2026-10-25 23:53:22浏览:588

本文详细解析如何使用 JavaScript 手动实现 Promise 核心功能。从构造函数、状态管理到 then 方法的链式调用,逐步讲解 resolve 与 reject 机制。涵盖 catch、finally 的特殊处理,以及 Promise.all 和 Promise.race 的底层逻辑,帮助开发者深入理解异步编程原理。

Promise 构造函数与状态管理

为了深入理解 Promise 的内部机制,我们将通过以下步骤逐步模拟实现其核心功能。

首先,需要创建一个构造函数,作为 Promise 实例的基础载体。

在构造函数中接收一个执行函数(executor),该函数接收两个参数:resolve 和 reject。构造函数内部会立即同步执行这个执行函数,而 resolve 或 reject 触发的回调则被安排为异步执行。

Promise 的状态一旦从 pending 变更为 fulfilled 或 rejected,便不可再更改。状态流转只能是 pending => fulfilled 或 pending => rejected。

then 方法实现与异常处理

在调用 then 方法时,必须处理传入参数的类型。successCallback 和 failCallback 可能并非函数,因此需要对此进行兼容处理。

对于默认的 failCallback,如果未提供,必须将异常重新抛出。这样做的目的是让异常能够冒泡,从而被后续的 Promise 链捕获。

在 then 中执行回调函数时,必须使用 try-catch 捕获可能出现的异常,并将这些异常传递给下一个 Promise,以确保错误处理的连贯性。

  • 如果 Promise 的状态尚未变更(仍为 pending),则需要将当前的回调方法添加到对应的成功或失败队列中,等待状态变更时执行。
  • 如果 Promise 的状态已经变更(fulfilled 或 rejected),则需要通过异步方式(如 setTimeout 或 microtask)来处理成功或失败的回调,以确保符合 Promise/A+ 规范中关于异步执行的约定。
  • 采用异步处理的原因在于,回调函数的执行结果可能与当前 then 返回的 Promise 实例一致,直接同步执行可能导致死循环问题,异步执行可有效避免此风险。

catch 与 finally 的特殊处理

catch 方法本质上是 then 方法的一种语法糖,仅传入 reject 回调,旨在简化错误处理的代码编写和理解。

finally 方法具有独特的行为特征,无论 Promise 最终是 resolve 还是 reject,它都会执行。

  • 无论 Promise 的状态如何变化,finally 中的回调函数都会被执行。
  • finally 接收的回调函数不接收任何参数,因为它不关心 Promise 的最终结果值或错误原因。
  • finally 方法返回一个新的 Promise,且其值可以穿透到后续的 then 或 catch 中。如果 finally 中抛出异常,新 Promise 将被 reject;否则,新 Promise 将沿用原 Promise 的状态和值。

静态方法:resolve 与 reject

Promise.resolve 和 Promise.reject 是静态方法,它们根据传入的参数直接返回一个对应状态(fulfilled 或 rejected)的 Promise 对象。

Promise.all 与 Promise.race 实现

Promise.all 方法用于处理多个 Promise 实例的并发执行,其核心特点如下。

  • Promise.all 返回一个新的 Promise 对象。
  • 当所有输入的 Promise 都成功(resolve)时,输出的 Promise 也会 resolve,且结果是一个数组,数组中的元素顺序与输入 Promise 的顺序保持一致。
  • 只有当所有输入的 Promise 都完成(无论成功或失败,但在 all 中通常指全部 resolve 才触发成功回调,若有一个 reject 则整体 reject)时,Promise.all 才会处理最终状态。为了实现这一逻辑,需要计数已完成的 Promise 数量。
  • 只要输入的 Promise 数组中有一个被 reject,Promise.all 返回的 Promise 就会立即被 reject,无需等待其他 Promise 完成。

Promise.race 方法用于返回第一个完成(无论成功或失败)的 Promise 结果,其特点如下。

  • Promise.race 返回一个新的 Promise 对象。
  • 当输入为数组时,输出结果取决于数组中第一个完成(resolve 或 reject)的 Promise 的值或状态。
  • 只要数组中有一个 Promise 执行了 resolve 或 reject,Promise.race 返回的 Promise 状态就会随之改变,并立即传递该结果。
const PENDING = 'pending' //等待
const FULFILLED = 'fulfilled' //成功
const REJECTED = 'rejected' //失败

const fulfilledCallback = [] //成功回调函数
const rejectedCallback = []  //失败回调函数

class MyPromise {
   
    constructor (executor) {
        
        try{
            executor(this.resolve, this.reject)
        } catch (e){
            this.reject(e)
        }
    }

    status = PENDING//promise的状态
    value = undefined//成功之后的值
    reason = undefined//失败之后的值
    fulfilledCallback = [] //成功回调函数
    rejectedCallback = []  //失败回调函数
    resolve = value => {
        //如果状态不是等待, 阻止程序继续往下执行
        if(this.status !== PENDING){
            return
        }
        this.status = FULFILLED
        this.value = value
        //判断成功回调是否存在,如果存在, 调用
        // this.fulfilledCallback && this.fulfilledCallback(this.value)
        while(this.fulfilledCallback.length) this.fulfilledCallback.shift()()

    }
    reject = reason => {
        //如果状态不是等待, 阻止程序继续往下执行
        if(this.status !== PENDING){
            return
        }
        this.status = REJECTED
        this.reason = reason
        //判断失败回调是否存在,如果存在, 调用
        // this.rejectedCallback && this.rejectedCallback(this.reason)
        while(this.rejectedCallback.length) this.rejectedCallback.shift()()
    }
    then = (fulfilledCallback, rejectedCallback) => {
        fulfilledCallback = fulfilledCallback ? fulfilledCallback : value => value
        rejectedCallback = rejectedCallback ? rejectedCallback : reason => {throw reason}
        let promise2 = new MyPromise((resolve, reject) => {
            
            //判断状态
            if(this.status === FULFILLED){
                setTimeout(() => {
                    try {
                        //判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
                        //如果是普通值,直接调用resolve
                        let x = fulfilledCallback(this.value)
                        //外面加载完,才能获取到promise2,用异步解决
                        resolvePromise(promise2,x,resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)
               
            }else if(this.status === REJECTED){
                
                setTimeout(() => {
                    try {
                        //判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
                        //如果是普通值,直接调用resolve
                        let x = rejectedCallback(this.reason)
                        //外面加载完,才能获取到promise2,用异步解决
                        resolvePromise(promise2,x,resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)
            }else{
                //等待状态
                this.fulfilledCallback.push(() => {
                    setTimeout(() => {
                        try {
                            //判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
                            //如果是普通值,直接调用resolve
                            let x = fulfilledCallback(this.value)
                            //外面加载完,才能获取到promise2,用异步解决
                            resolvePromise(promise2,x,resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    },0)
                });
                this.rejectedCallback.push(() => {
                    setTimeout(() => {
                        try {
                            //判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
                            //如果是普通值,直接调用resolve
                            let x = rejectedCallback(this.reason)
                            //外面加载完,才能获取到promise2,用异步解决
                            resolvePromise(promise2,x,resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    },0)
                });
            }
        })
        return promise2
    }

    static all (array) {
        let result= []
        let index = 0;

        return new MyPromise((resolve, reject) => {

            function addData (key, value) {
                result[key] = value
                index++
                if (index === array.length) {
                    resolve(result)
                }
            }

            for (let i = 0; i < array.length; i++) {
                
                if (array[i] instanceof MyPromise) {
                    //promise对象
                    array[i].then(value => addData(i, value), reason => reject(reason))
                } else {
                    //普通值, 放到数组里
                    addData(i, array[i])
                }
            }
        })

    }

    static resolve (value) {
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))

    }

    finally (callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {throw reason})
        })

    }

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

}

function resolvePromise(promise2,x,resolve, reject){

    if(x === promise2){
        return reject(new TypeError('啦啦啦啦'))
    }
    if(x instanceof MyPromise){
        //是promise
        //往下直接传
        x.then(resolve,reject)
    }else{
        //普通值
        resolve(x)
    }
}

module.exports = MyPromise;

至此,关于 JavaScript 手动实现 Promise 核心功能的示例代码讲解完毕。如需了解更多 JavaScript 实现 Promise 的相关内容,请搜索本站过往文章或继续浏览后续文章,感谢大家的支持!

作者最新文章