【前端】Promise对象的实现-JavaScript

发布于:2025-09-09 ⋅ 阅读:(22) ⋅ 点赞:(0)

完整代码:

class MyPromise {
    constructor(executor) {
        // 状态:pending、fulfilled、rejected
        this.state = 'pending';
        this.value = undefined; // 成功时的值
        this.reason = undefined; // 失败时的原因
        this.onFulfilledCallbacks = []; // 成功时的回调队列
        this.onRejectedCallbacks = []; // 失败时的回调队列

        const resolve = (value) => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
                this.onFulfilledCallbacks.forEach(fn => fn());
            }
        };

        const reject = (reason) => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn => fn());
            }
        };


        // 使用try-catch捕获执行器中的同步错误
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }

    // then 方法
    then(onFulfilled, onRejected) {
        // 处理参数可选性
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };

        // 实现链式调用
        let promise2 = new MyPromise((resolve, reject) => {
            const handleCallback = (callback, value) => {
                setTimeout(() => {
                    try {
                        let x = callback(value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
            };
            if (this.state === 'fulfilled') {
                handleCallback(onFulfilled, this.value);
            } else if (this.state === 'rejected') {
                handleCallback(onRejected, this.reason);
            } else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled, this.value));
                this.onRejectedCallbacks.push(() => handleCallback(onRejected, this.reason));
            }
        });
        return promise2
    }
    catch(onRejected) {
        return this.then(null, onRejected);
    }

    finally(onFinally) {
        return this.then(
            value => MyPromise.resolve(onFinally()).then(() => value),
            reason => MyPromise.resolve(onFinally().then(() => { throw reason; })
            );
    }
    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }

    static reject(reason) {
        return new Promise((resolve, reject) =>
            reject(reason));
    }

    static all(promises) {
        return new MyPromise((resolve, reject) => {
            const results = [];
            let remaining = promises.length;

            promises.forEach((promise, index) => {
                MyPromise.resolve(promise).then(
                    value => {
                        results[index] = value;
                        remaining--;
                        if (remaining == 0) {
                            resolve(results);
                        }
                    },
                    reason => reject(reason)
                );
            });
        });
    }
    static race(promise) {
        return new MyPromise((resolve, reject) => {
            promise.forEach(promise => {
                MyPromise.resolve(promise).then(resolve, reject);
            });
        });
    }
}
// resolvePromise函数
// 处理循环引用
// used 确保thenable的then方法只调用一次
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise'));
    }
    // 如果x是promise,递归解包直到非promise值
    if (x instanceof MyPromise) {
        x.then(y => resolvePromise(promise2, y, resolve, reject), reject);
        return;
    }
    // 如果x是thenable对象,具有then的方法的对象或函数,调用其then方法
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        let used;
        try {
            let then = x.then;
            if (typeof then === 'function') {
                then.call(
                    x,
                    y => {
                        if (used) return;
                        used = true;
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    r => {
                        if (used) return;
                        used = true;
                        reject(r);
                    }
                );
            } else {
                resolve(x);
            }
        } catch (error) {
            if (used) return;
            used = true;
            reject(error);
        }
    }
    else {
        resolve(x);
    }
}

逐步分析

定义属性。
回调队列用于存储 .then() 注册的异步回调,当状态改变时统一执行。
executor 是创建 Promise 时传入的函数(此时为形参)

constructor(executor) {
        // 状态:pending、fulfilled、rejected
        this.state = 'pending';
        this.value = undefined; // 成功时的值
        this.reason = undefined; // 失败时的原因
        this.onFulfilledCallbacks = []; // 成功时的回调队列
        this.onRejectedCallbacks = []; // 失败时的回调队列

只有在 pending 状态下才能改变状态(确保状态不可逆)。

const resolve = (value) => {
  if (this.state === 'pending') {
    this.state = 'fulfilled';
    this.value = value;
	// 执行所有通过 .then() 注册的成功回调(这些回调是在 pending 时注册的)。
    this.onFulfilledCallbacks.forEach(fn => fn()); 
  }
};

reject 函数与 resolve 函数类似,区别在于该函数保存返回的是失败原因,并执行所有失败回调。

const reject = (reason) => {
  if (this.state === 'pending') {
    this.state = 'rejected';
    this.reason = reason;
    this.onRejectedCallbacks.forEach(fn => fn());
  }
};

executor(resolve, reject) 表示执行传入的执行器函数,并以 resolve, reject 为参数。

以 resolve, reject为参数时,这是两个函数参数,这两个函数用于改变 Promise 的状态,并且把 value 或 reason 保存起来,供.then().catch()调用。

try {
  executor(resolve, reject); 
} catch (error) {
  reject(error); // 如果 executor 内部出错,直接 reject 
}

.then 方法用来听通知:Promise什么时候成功 / 失败,成功做了什么 / 做什么失败了。所有Promise实例必须有 .then方法。只有表示异步操作结果的对象才需要.then

onFulfilled 默认是 透传值:value => value(值穿透)
onRejected 默认是 抛出错误:error => { throw error }(错误继续向下传)

// then 方法
    then(onFulfilled, onRejected) {
        // 处理参数可选性
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };

实现链式调用:返回 promise2。

        // 实现链式调用
        let promise2 = new MyPromise((resolve, reject) => {
            const handleCallback = (callback, value) => {
                setTimeout(() => {
                    try {
                        let x = callback(value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
            };
            if (this.state === 'fulfilled') {
                handleCallback(onFulfilled, this.value);
            } else if (this.state === 'rejected') {
                handleCallback(onRejected, this.reason);
            } else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled, this.value));
                this.onRejectedCallbacks.push(() => handleCallback(onRejected, this.reason));
            }
        });
        return promise2
    }

单独对传入的形参 executor 进行分析。
handleCallback 函数是一个内部辅助函数,用来统一处理回调执行。
这里的callback又是函数形参,以后放用户传给.then()的函数如 onFulfilledonRejected
value 中传上一个Promise的成功值或失败原因。

(resolve, reject) => {
            const handleCallback = (callback, value) => {
            	// 异步执行
                setTimeout(() => {
                    try {
                        let x = callback(value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                });
            };

这里讲述一下resolvePromise的作用:根据 x 的类型决定如何设置 promise2 的状态。
如果 x 是普通值 → resolve(x)
如果 x 是 Promise → promise2 跟随它的状态

对于跟随状态的解释:
运动员 A(promise1)跑完 → 把接力棒交给 B
运动员 B(promise2)拿到棒 → 开始跑
B 的成绩取决于他自己的表现,而不是 A 的

如果 x 是 thenable → 调用它的 .then() 并等待
如果 x === promise2 → 循环引用,报错
如果 x 是对象且有 .then 方法 → 当作 thenable 处理

如果当前Promise已经成功,立即异步执行成功回调并传入成功值。
失败传原因balabalabala…

如果还没有执行,把这个回调函数放入等待队列,最开始创建的队列。

            if (this.state === 'fulfilled') {
                handleCallback(onFulfilled, this.value);
            } else if (this.state === 'rejected') {
                handleCallback(onRejected, this.reason);
            } else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled, this.value));
                this.onRejectedCallbacks.push(() => handleCallback(onRejected, this.reason));
            }
        });

每一个.then()返回的promise2都在等待前一个异步操作完成。

接下来实现catch函数,它只处理失败情况。
采取的措施是,一直传递失败。

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

然后实现finally函数,不管成功还是失败,都要执行它。成功传值,失败传错误。

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

static resolve用来返回一个已成功的Promise

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

static reject 用来创建一个已失败的Promise
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
等待所有 Promise 完成,如果都成功,返回结果数组;只要有一个失败,就立即失败。

static all(promises) {
  return new MyPromise((resolve, reject) => {
    const results = [];
    let remaining = promises.length;

    promises.forEach((promise, index) => {
      MyPromise.resolve(promise).then(
        value => {
          results[index] = value;
          remaining--;
          if (remaining == 0) {
            resolve(results);
          }
        },
        reason => reject(reason)
      );
    });
  });
}

只要有一个 Promise 完成(成功或失败),就采用它的结果。

static race(promises) {
  return new MyPromise((resolve, reject) => {
    promises.forEach(promise => {
      MyPromise.resolve(promise).then(resolve, reject);
    });
  });
}

同一个类中,写了const resolve又写了static resolve,它们之间没有冲突。虽然名字都是 resolve,但它们存在于完全不同的作用域和上下文中,不会互相干扰。reject同理。

在race和all中,直接调用了static resolve(value);而reject部分使用的是当前实例的reject函数。


网站公告

今日签到

点亮在社区的每一天
去签到