JS 入门通关手册(41):Promise 全解析(原理 + 手写 + 实战,面试必考)
本文详细讲解 JavaScript Promise 核心原理、状态流转、常用 API(then/catch/finally),结合实战场景说明 Promise 如何解决回调地狱,并提供可直接运行的手写 Promise 核心版代码。文章覆盖 Promise 高频面试考点与业务应用,帮助开发者彻底掌握异步编程基础,为后续 async/await、EventLoop 学习打下基础。
摘要
本文系统讲解 JavaScript Promise 核心原理、状态流转、常用 API 及实战场景,拆解回调地狱的解决方案,手把手实现符合 Promise/A+ 规范的核心版 Promise,结合大量可运行案例,覆盖日常开发与高频面试考点,帮助开发者彻底掌握异步编程基础,摆脱回调嵌套困境。
一、前言:为什么需要 Promise?
在 Promise 出现之前,JavaScript 异步编程完全依赖回调函数,当存在多层异步嵌套时,会出现 “回调地狱(Callback Hell)”,代码可读性、维护性极差,难以调试。
回调地狱痛点示例(真实场景)
javascript
运行
// 多层异步嵌套:获取用户信息 → 获取用户订单 → 获取订单详情
getUserInfo(userId, function(user) {
getUserOrder(user.id, function(order) {
getOrderDetail(order.id, function(detail) {
console.log(detail); // 嵌套3层已混乱,嵌套10层直接无法维护
}, function(err) { console.log(err); });
}, function(err) { console.log(err); });
}, function(err) { console.log(err); });
Promise 解决的核心问题
- 解决回调地狱,实现异步代码扁平化
- 统一异步错误处理,避免重复写错误回调
- 支持异步操作串行、并行控制
- 提供标准化的异步编程规范(Promise/A+ 规范)
二、Promise 核心概念
1. 定义
Promise 是一个异步操作的容器,用于表示一个异步操作的最终完成(成功)或失败(拒绝),并返回其结果值。
2. 核心特性
- Promise 有且只有三种状态,状态一旦改变,无法逆转(面试必记)
pending:初始状态,异步操作未完成fulfilled:成功状态,异步操作完成,返回结果rejected:失败状态,异步操作失败,返回错误信息
- 状态流转:
pending → fulfilled或pending → rejected(只能二选一) - 支持链式调用(
then方法),彻底摆脱回调嵌套
3. 基础语法(必背)
javascript
运行
// 1. 创建 Promise 实例
const promise = new Promise((resolve, reject) => {
// 异步操作(如接口请求、定时器)
setTimeout(() => {
const success = true;
if (success) {
// 成功:调用 resolve,传入结果
resolve("操作成功,返回数据");
} else {
// 失败:调用 reject,传入错误信息
reject(new Error("操作失败"));
}
}, 1000);
});
// 2. 调用 then 方法,处理成功/失败
promise.then(
(res) => {
console.log("成功:", res); // 接收 resolve 传入的值
},
(err) => {
console.log("失败:", err); // 接收 reject 传入的错误
}
);
三、Promise 常用 API 详解(实战必用)
1. then 方法(核心)
- 作用:注册异步操作的成功 / 失败回调
- 特点:返回一个新的 Promise,支持链式调用
- 注意:then 回调是微任务(后续第 44 篇详解)
javascript
运行
// 链式调用示例(解决回调地狱)
new Promise((resolve) => {
setTimeout(() => resolve(1), 1000);
})
.then((res) => {
console.log(res); // 1
return res + 1; // 返回值会作为下一个 then 的参数
})
.then((res) => {
console.log(res); // 2
return new Promise((resolve) => resolve(res + 1)); // 可返回 Promise
})
.then((res) => {
console.log(res); // 3
});
2. catch 方法(错误处理)
- 作用:专门处理 Promise 失败状态(替代 then 的第二个参数,更规范)
- 特点:捕获链式调用中所有前面的错误(包括 then 中的错误)
javascript
运行
new Promise((resolve, reject) => {
reject(new Error("初始错误"));
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log("捕获错误:", err.message); // 捕获初始错误
});
// 链式错误传递
new Promise((resolve) => resolve(1))
.then((res) => {
throw new Error("then 中的错误"); // 手动抛出错误
})
.then((res) => console.log(res))
.catch((err) => {
console.log("捕获错误:", err.message); // 捕获 then 中的错误
});
3. finally 方法(收尾操作)
- 作用:无论 Promise 成功还是失败,都会执行(如关闭加载 loading)
- 特点:不接收参数,不改变 Promise 的状态和结果
javascript
运行
new Promise((resolve, reject) => {
setTimeout(() => resolve("成功"), 1000);
})
.then((res) => console.log(res))
.catch((err) => console.log(err))
.finally(() => {
console.log("无论成功失败,都会执行(如关闭loading)");
});
4. 静态方法(基础)
Promise.resolve(value):快速创建一个成功状态的 PromisePromise.reject(error):快速创建一个失败状态的 Promise
javascript
运行
// 快速创建成功 Promise
Promise.resolve(100).then((res) => console.log(res)); // 100
// 快速创建失败 Promise
Promise.reject(new Error("失败")).catch((err) => console.log(err));
四、Promise 状态流转(面试必画)
1. 状态流转图(文字版,面试可口述)
plaintext
pending(初始)
↗️ ↘️
fulfilled(成功) rejected(失败)
↓ ↓
then 回调执行 catch 回调执行
↓ ↓
返回新 Promise 返回新 Promise
2. 关键注意点(面试避坑)
- 状态一旦改变(pending → fulfilled/rejected),无法再次改变
- 即使 Promise 已经成功 / 失败,再调用 resolve/reject 也无效
- then/catch/finally 都会返回新的 Promise,因此可以链式调用
- 未捕获的 Promise 错误,会触发浏览器 Uncaught Error
五、手写 Promise(核心版,面试必写)
核心思路(Promise/A+ 规范核心)
- 定义三种状态:pending、fulfilled、rejected
- 接收 executor 函数,立即执行,传入 resolve、reject 方法
- resolve 方法:将状态改为 fulfilled,保存成功结果,执行成功回调队列
- reject 方法:将状态改为 rejected,保存错误信息,执行失败回调队列
- then 方法:注册回调,若状态已改变,直接执行对应回调
手写代码(可直接运行,面试简化版)
javascript
运行
// 手写 Promise(符合 Promise/A+ 核心规范)
class MyPromise {
// 1. 初始化状态和结果
constructor(executor) {
this.status = "pending"; // 初始状态
this.value = undefined; // 成功结果
this.reason = undefined; // 失败原因
// 2. resolve 方法:修改状态为成功,保存结果
const resolve = (value) => {
if (this.status === "pending") {
this.status = "fulfilled";
this.value = value;
}
};
// 3. reject 方法:修改状态为失败,保存错误
const reject = (reason) => {
if (this.status === "pending") {
this.status = "rejected";
this.reason = reason;
}
};
// 4. 执行 executor,捕获同步错误
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
// 5. then 方法:注册回调
then(onFulfilled, onRejected) {
// 成功回调执行
if (this.status === "fulfilled") {
onFulfilled(this.value);
}
// 失败回调执行
if (this.status === "rejected") {
onRejected(this.reason);
}
}
}
// 测试手写 Promise
new MyPromise((resolve, reject) => {
setTimeout(() => resolve("手写 Promise 成功"), 1000);
}).then(
(res) => console.log(res),
(err) => console.log(err)
);
面试加分点
- 补充 “回调队列”(处理异步 then 回调),可升级为 “完整版手写”
- 说明:手写版本无需完全符合 Promise/A+ 所有细节,核心逻辑正确即可
六、Promise 实战场景(真实项目常用)
场景 1:接口请求封装(结合 axios)
javascript
运行
// 用 Promise 封装接口请求
function request(url, method = "GET") {
return new Promise((resolve, reject) => {
axios({ url, method })
.then((res) => resolve(res.data))
.catch((err) => reject(err));
});
}
// 使用(链式调用,无嵌套)
request("/api/user")
.then((user) => request(`/api/order?userId=${user.id}`))
.then((order) => request(`/api/orderDetail?orderId=${order.id}`))
.then((detail) => console.log(detail))
.catch((err) => console.log("请求错误:", err));
场景 2:异步操作串行执行
javascript
运行
// 需求:先获取用户,再获取订单,再获取详情(串行)
function getUser() {
return Promise.resolve({ id: 1, name: "张三" });
}
function getOrder(userId) {
return Promise.resolve({ id: 101, userId });
}
function getDetail(orderId) {
return Promise.resolve({ id: 1001, orderId, goods: "手机" });
}
// 串行执行
getUser()
.then((user) => getOrder(user.id))
.then((order) => getDetail(order.id))
.then((detail) => console.log(detail))
.catch((err) => console.log(err));
七、高频面试题(必背)
-
Promise 有哪三种状态?状态可以逆转吗?答:pending(初始)、fulfilled(成功)、rejected(失败);状态一旦改变,无法逆转。
-
Promise.then 为什么能链式调用?答:then 方法会返回一个新的 Promise,因此可以连续调用 then。
-
catch 能捕获哪些错误?答:捕获前面所有 Promise 的 rejected 状态,以及 then 回调中抛出的错误。
-
Promise.resolve 和 new Promise (resolve => resolve ()) 有区别吗?答:基本无区别,前者是后者的语法糖,更简洁。
-
手写 Promise 的核心要点是什么?答:定义三种状态、实现 resolve/reject 改变状态、then 方法注册回调。
八、总结
- Promise 是异步编程的标准化解决方案,解决回调地狱
- 三种状态不可逆转,pending → fulfilled 或 pending → rejected
- then/catch/finally 支持链式调用,实现异步操作扁平化
- 手写 Promise 核心:状态管理 + resolve/reject + then 回调注册
- 是后续 async/await、宏任务 / 微任务的基础,面试必考
更多推荐


所有评论(0)