Skip to content

手写Promise和Promise.then

手写一个Promise类

Promise需要满足以下几个条件:

  1. 状态只能从pending到fulfilled或rejected,且只能改变一次
  2. 回调函数需要传resolve和reject方法
  3. 需要立即执行传入的executor函数
代码展示
js
// 定义Promise构造函数(核心骨架)
function MyPromise(executor) {
    // 1. 初始化核心变量(记忆点:状态+结果+回调队列)
    this.status = 'pending'; // 初始状态:pending
    this.value = undefined;  // 成功结果
    this.reason = undefined; // 失败原因
    this.onFulfilledCallbacks = []; // 成功回调队列
    this.onRejectedCallbacks = [];  // 失败回调队列
    // 2. 定义resolve方法(改变状态+执行成功回调)
    const resolve = (value) => {
        // 记忆点:状态不可逆,只有pending能改
        if (this.status !== 'pending') return;
        this.status = 'fulfilled';
        this.value = value;
        // 执行队列里的所有成功回调(异步)
        this.onFulfilledCallbacks.forEach(cb => cb());
    };
    // 3. 定义reject方法(和resolve逻辑对称)
    const reject = (reason) => {
        if (this.status !== 'pending') return;
        this.status = 'rejected';
        this.reason = reason;
        // 执行队列里的所有失败回调(异步)
        this.onRejectedCallbacks.forEach(cb => cb());
    };
    // 4. 执行器函数(executor)立即执行,捕获同步错误
    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e); // 同步错误直接走reject
    }
}

实现Promise.then方法

Promise.then方法需要满足以下几个条件:

  1. then方法必须返回一个新的Promise
  2. 新Promise的状态由then方法的回调函数执行结果决定
  3. 如果then方法的回调函数返回一个Promise,那么新Promise的状态就会等待这个Promise的状态变化
  4. 如果then方法的回调函数抛出一个错误,那么新Promise的状态就会变成rejected
  5. then方法可以链式调用,每个then返回的都是一个新的Promise
  6. then方法的回调函数可以不传,默认值为值透传/错误透传
代码展示
js
// 实现then方法(面试核心,记模板)
MyPromise.prototype.then = function (onFulfilled, onRejected) {
    // 记忆点1:回调默认值(值透传/错误透传)
    // 没传onFulfilled,默认返回value;没传onRejected,默认抛出reason
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
    onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r };
    // 记忆点2:then必须返回新Promise(链式调用的关键)
    const newPromise = new MyPromise((resolve, reject) => {
        // 封装回调执行逻辑(复用成功/失败场景)
        const executeCallback = (callback, data) => {
            // 记忆点3:回调异步执行(用setTimeout模拟微任务,面试足够)
            setTimeout(() => {
                try {
                    // 执行回调,获取返回值
                    const result = callback(data);
                    // 记忆点4:处理回调返回值(如果是Promise,等待其完成)
                    if (result instanceof MyPromise) {
                        result.then(resolve, reject);
                    } else {
                        // 非Promise,直接resolve给下一个then
                        resolve(result);
                    }
                } catch (e) {
                    // 回调执行出错,直接reject给下一个then
                    reject(e);
                }
            }, 0);
        };
        // 分三种状态处理
        if (this.status === 'fulfilled') {
            // 状态已成功:执行成功回调
            executeCallback(onFulfilled, this.value);
        } else if (this.status === 'rejected') {
            // 状态已失败:执行失败回调
            executeCallback(onRejected, this.reason);
        } else {
            // 状态pending:把回调存入队列(等resolve/reject后执行)
            this.onFulfilledCallbacks.push(() => {
                executeCallback(onFulfilled, this.value);
            });
            this.onRejectedCallbacks.push(() => {
                executeCallback(onRejected, this.reason);
            });
        }
    });
    return newPromise;
};

实现Promise.catch方法

js
// 可选:补充catch方法(简化错误捕获,面试加分)
MyPromise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected);
};