前言
Promise作为JavaScript异步编程的核心概念,是现代前端开发中不可或缺的重要知识点。本文将手写两个版本的Promise实现:一个简单版和一个完整版,帮助你彻底掌握Promise的内部机制。
什么是Promise?
Promise是一种异步编程的解决方案,用于处理异步操作的结果。它具有以下特点:
- 三种状态:pending(等待中)、fulfilled(已成功)、rejected(已失败)
- 状态不可逆:状态一旦改变,就不能再变
- 链式调用:可以避免回调地狱
- 统一的错误处理:提供了catch方法进行错误捕获
简单版Promise实现
我们先从一个最简单的Promise实现开始,理解Promise的基本结构:
class simplePromise {
constructor(excutor) {
// Promise的三种状态:pending(等待中)、fulfilled(已成功)、rejected(已失败)
this.status = 'pending' // 初始状态为pending
this.value = undefined // 存储成功时的返回值
this.reason = undefined // 存储失败时的原因
this.onFulfilledCallbacks = [] // 存储成功回调函数的队列
this.onRejectedCallbacks = [] // 存储失败回调函数的队列
// resolve函数:将Promise状态从pending改为fulfilled
const resolve = (value) => {
// 只有在pending状态下才能改变状态(状态不可逆)
if (this.status === 'pending') {
this.status = 'fulfilled' // 更新状态为fulfilled
this.value = value // 存储成功的值
// 执行所有已注册的成功回调函数
this.onFulfilledCallbacks.forEach(fn => fn(this.value))
}
}
// reject函数:将Promise状态从pending改为rejected
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected' // 更新状态为rejected
this.reason = reason // 存储失败的原因
// 执行所有已注册的失败回调函数
this.onRejectedCallbacks.forEach(fn => fn(this.reason))
}
}
// 立即执行executor函数,捕获可能的同步错误
try {
excutor(resolve, reject) // 将resolve和reject函数作为参数传入
} catch (error) {
// 如果executor执行过程中抛出错误,直接调用reject
reject(error)
}
}
// then方法:添加成功和失败的回调函数,支持链式调用
then(onFulfilled, onRejected) {
// 处理参数可能不是函数的情况(值穿透)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
// 返回新的Promise实例,实现链式调用
return new simplePromise((resolve, reject) => {
// 处理fulfilled状态的函数
const handleFulfilled = () => {
try {
// 执行成功回调,获取返回值
const result = onFulfilled(this.value)
// 将返回值传递给新的Promise
resolve(result)
} catch (error) {
// 如果回调执行出错,reject错误
reject(error)
}
}
// 处理rejected状态的函数
const handleRejected = () => {
try {
// 执行失败回调,获取返回值
const result = onRejected(this.reason)
// 将返回值传递给新的Promise(即使失败回调也可能返回成功值)
resolve(result)
} catch (error) {
reject(error)
}
}
// 根据当前Promise的状态执行相应的处理
if (this.status === 'fulfilled') {
// 如果当前Promise已经是fulfilled状态,立即执行成功回调
handleFulfilled()
} else if (this.status === 'rejected') {
// 如果当前Promise已经是rejected状态,立即执行失败回调
handleRejected()
} else if (this.status === 'pending') {
// 如果当前Promise还是pending状态,将回调函数加入队列等待执行
this.onFulfilledCallbacks.push(handleFulfilled)
this.onRejectedCallbacks.push(handleRejected)
}
})
}
}
简单版实现要点解析:
- 状态管理:通过status属性管理三种状态
- 回调队列:使用数组存储pending状态下的回调函数
- then方法:返回新的Promise实例,支持链式调用
- 错误处理:使用try-catch捕获执行过程中的错误
完整版Promise实现(符合Promise/A+规范)
接下来我们实现一个符合Promise/A+规范的完整版本,包含所有常用方法:
// Promise的三种状态常量定义
const PENDING = 'pending'; // 等待中:初始状态
const FULFILLED = 'fulfilled'; // 已成功:操作成功完成
const REJECTED = 'rejected'; // 已失败:操作失败
class MyPromise {
constructor(executor) {
// 初始化Promise实例的状态和值
this.status = PENDING; // 初始状态为pending
this.value = null; // 存储成功时的值
this.reason = null; // 存储失败时的原因
this.onFulfilledCallbacks = []; // 成功回调函数队列
this.onRejectedCallbacks = []; // 失败回调函数队列
// resolve函数:将Promise状态从pending改为fulfilled
const resolve = (value) => {
// 只有在pending状态下才能改变状态(状态不可逆原则)
if (this.status === PENDING) {
this.status = FULFILLED; // 更新状态为fulfilled
this.value = value; // 存储成功的值
// 异步执行所有已注册的成功回调函数
this.onFulfilledCallbacks.forEach(callback => callback());
}
};
// reject函数:将Promise状态从pending改为rejected
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED; // 更新状态为rejected
this.reason = reason; // 存储失败的原因
// 异步执行所有已注册的失败回调函数
this.onRejectedCallbacks.forEach(callback => callback());
}
};
// 立即同步执行executor函数,捕获可能的同步错误
try {
executor(resolve, reject); // 传入resolve和reject函数
} catch (error) {
// 如果executor执行过程中抛出同步错误,直接调用reject
reject(error);
}
}
// then方法:Promise的核心方法,用于添加成功和失败的回调,支持链式调用
then(onFulfilled, onRejected) {
// 处理参数可能不是函数的情况(值穿透机制)
// 如果onFulfilled不是函数,创建一个默认函数直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// 如果onRejected不是函数,创建一个默认函数抛出reason
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
// 创建新的Promise实例(promise2),用于链式调用
const promise2 = new MyPromise((resolve, reject) => {
// 处理当前Promise已经是fulfilled状态的情况
if (this.status === FULFILLED) {
// 使用setTimeout确保回调异步执行(符合Promise/A+规范)
setTimeout(() => {
try {
// 执行成功回调函数,获取返回值x
const x = onFulfilled(this.value);
// 处理返回值,确保链式调用的正确性
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果回调执行过程中抛出错误,直接reject
reject(error);
}
}, 0);
}
// 处理当前Promise已经是rejected状态的情况
if (this.status === REJECTED) {
setTimeout(() => {
try {
// 执行失败回调函数,获取返回值x
const x = onRejected(this.reason);
// 处理返回值
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 处理当前Promise还是pending状态的情况
if (this.status === PENDING) {
// 将成功回调包装后加入队列,等待状态改变时执行
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
// 将失败回调包装后加入队列,等待状态改变时执行
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
// 返回新的Promise实例,实现链式调用
return promise2;
}
// catch方法:处理Promise链中的错误,是then(null, onRejected)的语法糖
// 用于捕获Promise链中任何位置的错误,简化错误处理代码
catch(onRejected) {
// 调用then方法,第一个参数传null,只处理rejected状态
return this.then(null, onRejected);
}
// finally方法:无论Promise成功或失败都会执行的回调
// 常用于清理操作,如关闭数据库连接、隐藏加载动画等
finally(onFinally) {
return this.then(
// 成功时:执行callback,然后返回原始value
value => MyPromise.resolve(onFinally()).then(() => value),
// 失败时:执行callback,然后重新抛出原始reason
reason => MyPromise.resolve(onFinally()).then(() => { throw reason; })
);
}
// 静态方法:Promise.resolve - 创建一个已解决的Promise
// 如果传入的值已经是Promise,直接返回;否则包装成已解决的Promise
static resolve(value) {
if (value instanceof MyPromise) {
return value; // 已经是Promise,直接返回
}
// 包装普通值为已解决的Promise
return new MyPromise(resolve => resolve(value));
}
// 静态方法:Promise.reject - 创建一个已拒绝的Promise
// 直接返回一个立即拒绝的Promise实例
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
// 静态方法:Promise.all - 等待所有Promise完成
// 所有Promise都成功时返回结果数组,任何一个失败立即拒绝
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = []; // 存储所有Promise的结果
let count = 0; // 计数器,记录已完成的Promise数量
// 处理空数组情况
if (promises.length === 0) {
return resolve(results); // 空数组直接返回空结果
}
// 遍历所有Promise
promises.forEach((promise, index) => {
// 确保每个元素都是Promise(使用Promise.resolve包装)
MyPromise.resolve(promise).then(
// 成功回调:将结果存入对应位置
value => {
results[index] = value; // 保持结果顺序与输入一致
count++;
// 检查是否所有Promise都已完成
if (count === promises.length) {
resolve(results); // 全部成功,返回结果数组
}
},
// 失败回调:任何一个失败立即拒绝整个Promise
reject
);
});
});
}
// 静态方法:Promise.race - 竞速,返回最先完成的Promise结果
// 无论是成功还是失败,第一个完成的Promise决定最终结果
static race(promises) {
return new MyPromise((resolve, reject) => {
// 处理空数组情况
if (promises.length === 0) {
return; // 空数组,Promise永远pending
}
// 遍历所有Promise,第一个完成的决定最终结果
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
// 静态方法:Promise.allSettled - 等待所有Promise完成(无论成功失败)
// 返回包含所有Promise状态和结果的对象数组
static allSettled(promises) {
return new MyPromise(resolve => {
const results = []; // 存储所有Promise的状态和结果
let count = 0; // 计数器
if (promises.length === 0) {
return resolve(results); // 空数组直接返回
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
// 成功:记录fulfilled状态和值
value => {
results[index] = { status: FULFILLED, value };
count++;
if (count === promises.length) {
resolve(results);
}
},
// 失败:记录rejected状态和原因
reason => {
results[index] = { status: REJECTED, reason };
count++;
if (count === promises.length) {
resolve(results);
}
}
);
});
});
}
// 静态方法:Promise.any - 返回第一个成功的Promise
// 如果所有Promise都失败,返回AggregateError包含所有错误
static any(promises) {
return new MyPromise((resolve, reject) => {
const errors = []; // 存储所有失败的原因
let count = 0; // 计数器
if (promises.length === 0) {
// 空数组,返回包含空错误数组的AggregateError
return reject(new AggregateError([], 'All promises were rejected'));
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
// 成功:立即resolve第一个成功的Promise
resolve,
// 失败:记录错误,检查是否所有Promise都失败
reason => {
errors[index] = reason; // 记录每个Promise的失败原因
count++;
// 所有Promise都失败时,返回AggregateError
if (count === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
}
}
// resolvePromise函数:处理Promise链式调用中的返回值,确保符合Promise/A+规范
// 这是Promise实现中最复杂的部分,负责处理then方法返回值的各种情况
function resolvePromise(promise2, x, resolve, reject) {
// 检查循环引用:如果promise2和x是同一个对象,抛出TypeError
// 防止出现 promise.then(() => promise) 这样的循环引用
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 标记是否已经调用过resolve或reject,确保只调用一次
let called = false;
// 如果x是对象或函数(可能是Promise或thenable对象)
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
// 获取x的then方法(如果x是Promise,then方法应该存在)
const then = x.then;
// 如果then是函数,将x视为Promise或thenable对象
if (typeof then === 'function') {
// 调用x的then方法,传入resolve和reject回调
then.call(
x,
// resolve回调:当x成功时,递归调用resolvePromise处理返回值y
y => {
if (called) return; // 确保只调用一次
called = true;
// 递归处理y,因为y可能也是一个Promise
resolvePromise(promise2, y, resolve, reject);
},
// reject回调:当x失败时,直接reject原因r
r => {
if (called) return; // 确保只调用一次
called = true;
reject(r);
}
);
} else {
// 如果then不是函数,说明x是普通对象,直接resolve
resolve(x);
}
} catch (error) {
// 如果获取then或调用then时出错,直接reject错误
if (called) return; // 确保只调用一次
called = true;
reject(error);
}
} else {
// 如果x不是对象或函数(是基本类型值),直接resolve
resolve(x);
}
}
核心实现要点解析
1. 状态管理机制
Promise的状态管理是其核心特性之一:
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 状态一旦改变,就不能再变
if (this.status === PENDING) {
this.status = FULFILLED; // 或 REJECTED
// ...
}
2. 异步执行保证
为了符合Promise/A+规范,then方法的回调必须异步执行:
setTimeout(() => {
// 异步执行回调
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
}, 0);
3. 链式调用实现
then方法返回新的Promise实例,实现链式调用:
then(onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
// ...
});
return promise2;
}
4. Promise解析过程
resolvePromise函数处理then方法返回值的各种情况:
- 普通值:直接resolve
- Promise对象:等待其状态改变
- thenable对象:调用其then方法
- 循环引用:抛出TypeError
常用静态方法实现
Promise.resolve()
将值转换为Promise对象:
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise((resolve) => {
resolve(value);
});
}
Promise.all()
等待所有Promise完成:
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let count = 0;
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
count++;
if (count === promises.length) {
resolve(results);
}
},
reject
);
});
});
}
Promise.race()
返回第一个完成的Promise:
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
测试用例
让我们测试一下实现的正确性:
// 基本功能测试
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功了!');
}, 1000);
});
promise1.then(
value => console.log('成功:', value),
reason => console.log('失败:', reason)
);
// 链式调用测试
new MyPromise((resolve) => setTimeout(() => resolve(1), 1000))
.then(value => {
console.log('第一步:', value);
return value + 1;
})
.then(value => {
console.log('第二步:', value);
return value + 1;
})
.then(value => {
console.log('第三步:', value);
});
// 静态方法测试
MyPromise.all([
MyPromise.resolve(1),
new MyPromise(resolve => setTimeout(() => resolve(2), 500)),
new MyPromise(resolve => setTimeout(() => resolve(3), 1000))
]).then(values => {
console.log('all方法结果:', values); // [1, 2, 3]
});
总结
通过手写Promise实现,可以深入理解:
- Promise的状态机制:三种状态及其不可逆特性
- 异步执行原理:使用setTimeout保证回调异步执行
- 链式调用实现:then方法返回新Promise
- 错误处理机制:统一的catch方法
- 静态方法原理:resolve、reject、all、race等