目录
- 前言:为什么需要 Promise?
- Promise 的基础使用
- Promise 的运行机制:事件循环与微任务
- 手写 Promise 源码
- Promise 实际应用案例
- Promise 与 async/await 的关系
- 总结
- 参考资料
一、前言:为什么需要 Promise?
在 JavaScript 早期,异步任务主要通过 回调函数(callback)实现。但回调容易导致“回调地狱”:层层嵌套、难以维护。
Promise 的出现就是为了解决 异步流程的可读性和可维护性 问题。
二、Promise 的基础使用
1. 创建与状态
Promise 有三种状态:
pending(进行中)fulfilled(已成功)rejected(已失败)
一旦状态从 pending 变为 fulfilled 或 rejected,就不能再改变。
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功结果");
// 或者 reject("失败原因");
}, 1000);
});
p.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log("任务结束"));
2. then / catch / finally
then:接收成功结果catch:接收失败原因finally:无论成功失败都会执行
fetch("/api/data")
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err))
.finally(() => console.log("请求结束"));
3. Promise 的静态方法
Promise.resolve(value)Promise.reject(error)Promise.all([...]):全部成功才成功,有一个失败就失败Promise.race([...]):谁先返回结果就采用谁Promise.allSettled([...]):无论成功失败都收集结果Promise.any([...]):只要有一个成功就返回
Promise.all([fetch("/a"), fetch("/b")])
.then(([resA, resB]) => console.log(resA, resB));
三、Promise 的运行机制:事件循环与微任务
Promise 的回调(then/catch/finally)属于 微任务。
执行顺序规则:
- 先执行同步代码。
- 再执行所有微任务(Promise 回调)。
- 最后执行下一个宏任务(如 setTimeout)。
例子:
console.log("start");
setTimeout(() => console.log("timeout"));
Promise.resolve().then(() => console.log("promise"));
console.log("end");
// 输出顺序: start → end → promise → timeout
四、手写 Promise 源码
1. 最小可用版
class MyPromise {
constructor(executor) {
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 {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
if (this.state === "fulfilled") {
onFulfilled(this.value);
} else if (this.state === "rejected") {
onRejected(this.reason);
} else {
this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
this.onRejectedCallbacks.push(() => onRejected(this.reason));
}
}
}
2. 支持链式调用(核心)
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
if (this.state === "fulfilled") {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (err) {
reject(err);
}
}
if (this.state === "rejected") {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (err) {
reject(err);
}
}
if (this.state === "pending") {
this.onFulfilledCallbacks.push(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (err) {
reject(err);
}
});
this.onRejectedCallbacks.push(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (err) {
reject(err);
}
});
}
});
}
这样就支持链式调用:
new MyPromise((resolve) => resolve(1))
.then(res => res + 1)
.then(res => console.log(res)); // 输出 2
五、Promise 实际应用案例
1. 并发请求优化
async function getData() {
const [user, posts] = await Promise.all([
fetch("/user").then(r => r.json()),
fetch("/posts").then(r => r.json())
]);
console.log(user, posts);
}
2. 网络请求失败重试
function fetchWithRetry(url, times = 3) {
return new Promise((resolve, reject) => {
function attempt(n) {
fetch(url).then(resolve).catch(err => {
if (n === 0) reject(err);
else attempt(n - 1);
});
}
attempt(times);
});
}
六、Promise 与 async/await 的关系
async/await是基于 Promise 的语法糖。await后面必须是 Promise 或值。- 用
try/catch捕获异常,更直观。
async function loadData() {
try {
const data = await fetch("/api").then(r => r.json());
console.log(data);
} catch (err) {
console.error(err);
}
}
七、总结
- Promise 解决了异步回调地狱问题。
- 核心机制是 状态不可逆 + 微任务调度。
- 掌握手写 Promise,有助于深入理解其原理。
- 在现代开发中,Promise 与 async/await 是前端必备技能。