You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写支持Promise.resolve()的Promise polyfill

Promise Polyfill 编写问题解答

问题背景

我正在尝试编写Promise polyfill以加深对Promise原理的理解,在网上检索到一段可部分理解的函数式实现代码,但存在几个待解决的问题:

  • 无法理解代码中handlers和catchers数组的作用,资料说明二者用于处理Promise尚未落定(既未fulfilled也未rejected)的场景
  • 不理解resolve、reject方法中遍历两个数组执行回调的两行代码逻辑
  • 现有实现不支持类似let p1 = Promise.resolve("Hello World");的静态调用写法,尝试改写为class类实现版本未成功
  • 曾尝试编写CustomPromise.prototype.resolve = function(error) {...}挂载方法,依然报错CustomPromise.resolve is not a function;类实现版本中未正确实现executor回调逻辑,只需要任意一种实现方案可支持Promise.resolve()调用场景即可。

初始参考代码(函数式版本)

// 注:原代码未定义状态常量,需提前声明
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function CustomPromise(executor) {
var state=PENDING;
var value = null;
var handlers=[];
var catchers = [];

function resolve(result) {
    if(state!==PENDING) return;

    state=FULFILLED;
    value = result;

    handlers.forEach((h)=>h(value));    // 待解释的遍历逻辑
}

function reject(error) {
    if(state!==PENDING)return;

    state=REJECTED;
    value=error;
    catchers.forEach(c=>c(value));  // 待解释的遍历逻辑
}

this.then = function(successCallback) {
    if(state === FULFILLED) {
        successCallback(value);
    }else {
        handlers.push(successCallback);
    }
    return this;
}

this.catch = function(failureCallback) {
    if(state===REJECTED){
        failureCallback(value)
    } else {
        catchers.push(value); // 原代码此处存在bug
    }
}
executor(resolve,reject);
}

存在问题的自写类版本

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class CustomPromise {
constructor(callback){
    this.state = PENDING;
    this.executor = callback;
    this.value = null;
    this.handlers = [];
    this.catchers = [];
    this.then = function(successCallback) {
        if(this.state === FULFILLED) {
            successCallback(this.value);
        }else {
            this.handlers.push(successCallback);
        }
        return this;
    };

    this.catch = function(failureCallback) {
        if(this.state===REJECTED){
            failureCallback(this.value)
        } else {
            this.catchers.push(this.value); // 同函数式版本的bug
        }
    };
}

static resolve(result) {
    if(this.state!==PENDING) return;

    this.state=FULFILLED;
    this.value = result;

    this.handlers.forEach((h)=>h(this.value));
}

static reject(error) {
    if(this.state!==PENDING)return;

    this.state=REJECTED;
    this.value=error;
    this.catchers.forEach(c=>c(this.value));
}
}

核心逻辑解释

handlers和catchers数组的作用

Promise支持异步状态落定:当调用.then/.catch注册回调时,Promise很可能还处于PENDING状态(比如封装了setTimeout、接口请求等异步操作),此时传入的成功/失败回调不能立刻执行,需要先暂存。

  • handlers:存储PENDING状态下通过.then注册的所有成功回调
  • catchers:存储PENDING状态下通过.catch注册的所有失败回调

注:两份初始代码的catch方法都存在bug:PENDING状态下应该把传入的failureCallback推入catchers数组,原代码错误推入了value,会导致后续reject时执行报错。

遍历数组执行回调的逻辑

Promise状态只能从PENDING变更为FULFILLED/REJECTED,且一旦变更不可逆。当调用resolve将状态改为FULFILLED、调用reject将状态改为REJECTED时,需要把之前暂存的所有对应回调按注册顺序依次执行,传入最终的结果/错误值,这就是两行遍历代码的作用。

静态方法报错原因

给CustomPromise.prototype挂载方法,是给Promise实例添加方法,需要通过new CustomPromise().resolve()的形式才能调用;而CustomPromise.resolve()是直接将构造函数/类本身作为对象调用方法,属于静态方法,需要直接挂载到构造函数对象上,类中用static关键字定义的方法就会挂载到类本身,而非原型链。


修正后可运行的函数式实现版本(支持静态调用)

修正了原代码的bug,补全了executor执行逻辑、静态resolve/reject实现,同时支持基础的链式调用:

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function CustomPromise(executor) {
    this.state = PENDING
    this.value = null
    this.handlers = []
    this.catchers = []

    const resolve = (result) => {
        if (this.state !== PENDING) return
        // 支持resolve传入Promise实例的场景
        if (result instanceof CustomPromise) {
            return result.then(resolve, reject)
        }
        this.state = FULFILLED
        this.value = result
        this.handlers.forEach(cb => cb(this.value))
    }

    const reject = (error) => {
        if (this.state !== PENDING) return
        this.state = REJECTED
        this.value = error
        this.catchers.forEach(cb => cb(this.value))
    }

    this.then = function(onFulfilled, onRejected) {
        // 链式调用必须返回新的Promise实例
        return new CustomPromise((resolveNext, rejectNext) => {
            const handleSuccess = (val) => {
                try {
                    const res = onFulfilled ? onFulfilled(val) : val
                    resolveNext(res)
                } catch (err) {
                    rejectNext(err)
                }
            }
            const handleFail = (err) => {
                try {
                    const res = onRejected ? onRejected(err) : err
                    onRejected ? resolveNext(res) : rejectNext(res)
                } catch (e) {
                    rejectNext(e)
                }
            }

            if (this.state === FULFILLED) {
                handleSuccess(this.value)
            } else if (this.state === REJECTED) {
                handleFail(this.value)
            } else {
                this.handlers.push(handleSuccess)
                this.catchers.push(handleFail)
            }
        })
    }

    this.catch = function(onRejected) {
        return this.then(null, onRejected)
    }

    // 执行用户传入的executor,捕获同步错误
    try {
        executor(resolve, reject)
    } catch (err) {
        reject(err)
    }
}

// 直接挂载静态方法到构造函数
CustomPromise.resolve = function(value) {
    if (value instanceof CustomPromise) return value
    return new CustomPromise(resolve => resolve(value))
}

CustomPromise.reject = function(error) {
    return new CustomPromise((_, reject) => reject(error))
}

测试用例

// 测试静态resolve
const p1 = CustomPromise.resolve("Hello World")
p1.then(res => console.log(res)) // 输出 Hello World

// 测试异步场景
const p2 = new CustomPromise((resolve) => {
    setTimeout(() => resolve("异步执行成功"), 1000)
})
p2.then(res => console.log(res)) // 1秒后输出 异步执行成功

// 测试链式调用
CustomPromise.resolve(1).then(res => res + 2).then(res => console.log(res)) // 输出3

内容的提问来源于stack exchange,提问作者era s'q

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:48:17