本文将从零开始,一步步实现一个符合 Promise/A+ 规范的 Promise。
NOTE本文假设你已经了解 Promise 的基本用法。如果你还不熟悉 Promise,建议先阅读 MDN Promise 指南。
目录
Promise 基础特性
在开始手写实现之前,让我们先通过一些典型的使用案例来理解 Promise 的核心特性。这些案例涵盖了 Promise 的主要使用场景,将帮助我们更好地理解实现细节。
1. 基本构造与使用
最基本的 Promise 使用方式是通过构造函数创建实例,并通过 then/catch 处理结果:
// 创建一个异步操作的 Promise const promise = new Promise<string>((resolve, reject) => { // 模拟异步操作 setTimeout(() => { const random = Math.random(); if (random > 0.5) { resolve(`成功: ${random}`); // 异步操作成功 } else { reject(`失败: ${random}`); // 异步操作失败 } }, 1000); }); // 处理 Promise 的结果 promise .then(result => { console.log(result); // 输出: 成功: 0.7xxxx }) .catch(error => { console.log(error); // 输出: 失败: 0.3xxxx });
WARNINGPromise 构造函数的参数是一个执行器函数(executor),它接收两个参数:resolve 和 reject。 executor 函数在 Promise 构造函数执行时会立即执行。
2. 链式调用
Promise 的一个重要特性是支持链式调用,每个 then 方法都返回一个新的 Promise:
const chainPromise = new Promise<number>((resolve) => { resolve(1); }); chainPromise .then(value => { console.log(value); // 1 return value + 1; // 返回值会被包装成新的 Promise }) .then(value => { console.log(value); // 2 return value + 1; // 继续传递给下一个 then }) .then(value => { console.log(value); // 3 });
TIPthen 方法的返回值会被自动包装成 Promise。这使得我们可以方便地进行链式调用,处理异步操作的连续步骤。
3. 错误处理机制
Promise 提供了两种错误处理方式,使用 catch 或在 then 中处理:
const errorPromise = new Promise<never>((resolve, reject) => { throw new Error('发生错误!'); // 直接抛出错误 }); // 方式一:使用 catch 捕获错误 errorPromise .then(value => { console.log('这里不会执行'); }) .catch(error => { console.log('捕获到错误:', error.message); }); // 方式二:在 then 的第二个参数中处理错误 errorPromise.then( value => { console.log('这里不会执行'); }, error => { console.log('在 then 中捕获错误:', error.message); } );
WARNING在 Promise 链中,如果没有正确处理错误,错误会沿着 Promise 链向下传播,直到遇到错误处理器。 建议在 Promise 链的末尾始终添加 catch 处理器。
4. 状态的单向性
Promise 的状态一旦改变就不可逆转,这保证了异步操作的可靠性:
const statePromise = new Promise<string>((resolve, reject) => { resolve('成功'); // 状态变更为 fulfilled reject('失败'); // 这次调用将被忽略 }); statePromise .then(value => { console.log(value); // 输出: 成功 }) .catch(error => { console.log(error); // 永远不会执行 });
Promise 的状态只能从 pending 变为 fulfilled 或 rejected。 一旦状态改变,就不能再变。这就是 Promise 名字的由来 - 它是一个”承诺”。
实现 MyPromise
理解了 Promise 的核心特性,我们可以开始实现自己的 Promise 了。让我们从最基础的功能开始,逐步构建一个符合 Promise/A+ 规范的实现。
1. 基础版本
首先实现 Promise 的基本功能:构造器和 then 方法。为了简化实现,我们先只考虑成功的情况(fulfilled 状态):
class MyPromise<T> { #status: 'pending' | 'fulfilled' = 'pending' #value?: T #tasks: Array<() => void> = [] #resolve = (value: T) => { this.#value = value this.#status = 'fulfilled' this.#tasks.forEach(task => task()) } constructor(executor: (resolve: (value: T) => void) => void) { executor(this.#resolve) } then(onFulfilled: (value: T) => void) { if (this.#status === 'fulfilled') { onFulfilled(this.#value!) } else { this.#tasks.push(() => { queueMicrotask(() => onFulfilled(this.#value!)) }) } } }
这个基础实现包含了 Promise 的核心机制:
- 状态管理:使用 #status 追踪 Promise 的状态
- 值存储:使用 #value 存储 Promise 的结果
- 任务队列:使用 #tasks 存储待执行的回调函数
2. 支持链式调用
为了支持链式调用,我们需要修改 then 方法,使其返回一个新的 Promise:
class MyPromise<T> { #status: 'pending' | 'fulfilled' = 'pending' #value?: T #tasks: Array<() => void> = [] #resolve = (value: T) => { this.#value = value this.#status = 'fulfilled' this.#tasks.forEach(task => task()) } constructor(executor: (resolve: (value: T) => void) => void) { executor(this.#resolve) } then<R>(onFulfilled: (value: T) => R) { return new MyPromise<R>((resolve) => { if (this.#status === 'fulfilled') { const newValue = onFulfilled(this.#value!) resolve(newValue) } else { this.#tasks.push(() => { queueMicrotask(() => { const newValue = onFulfilled(this.#value!) resolve(newValue) }) }) } }) } }
这个改进版本的关键点是:
- then 方法现在返回新的 Promise
- 使用泛型 R 表示 then 回调的返回值类型
- 将回调的返回值传递给新 Promise 的 resolve
NOTE接下来的步骤将包括:
- 添加 rejected 状态的支持
- 实现错误处理机制
- 添加 catch 和 finally 方法
- 实现静态方法(如 Promise.all, Promise.race 等)