← 返回首页
文章
2026-03-31
Promise 完全指南
Promise 完全指南:从入门到手写实现 一篇文章彻底搞懂 Promise:基础方法、静态方法、手写实现,附完整代码示例 一、核心概念 1.1 什么是 Promise?(大白话解释) Promise 就是一个"承诺"—...
Promise 完全指南:从入门到手写实现 #
一篇文章彻底搞懂 Promise:基础方法、静态方法、手写实现,附完整代码示例
一、核心概念 #
1.1 什么是 Promise?(大白话解释) #
Promise 就是一个"承诺"——表示一个未来才会知道结果的操作。
打个比方:你去餐厅点餐,服务员给你一个"排队号牌",这就是 Promise。你不知道餐什么时候做好,但你可以:
- 等餐做好了(成功 resolve)→ 服务员叫号取餐
- 等餐做失败了(失败 reject)→ 服务员告诉你"不好意思,食材没了"
传统回调 vs Promise 对比:
// 传统回调写法 —— 套娃地狱(Callback Hell)
getUserInfo(userId, function(user) {
getUserOrders(user.id, function(orders) {
getOrderDetails(orders[0].id, function(details) {
console.log(details);
});
});
});
// Promise 写法 —— 链式调用,清晰优雅
getUserInfo(userId)
.then(user => getUserOrders(user.id))
.then(orders => getOrderDetails(orders[0].id))
.then(details => console.log(details))
.catch(err => console.error(err));1.2 为什么需要 Promise? #
Promise 解决了三个核心问题:
| 问题 | 传统回调的痛点 | Promise 的解决方案 |
|---|---|---|
| 回调地狱 | 嵌套层层叠叠,难以维护 | 链式调用 .then(),扁平化 |
| 错误处理 | 每个 callback 都要单独处理 error | 统一用 .catch() 捕获 |
| 状态管理 | 无法知道异步操作进行到哪一步 | 三种状态:pending、fulfilled、rejected |
1.3 Promise 的三种状态 #
// Promise 状态图
//
// pending(进行中)──────┬──→ fulfilled(已成功)
// │
// └──→ rejected(已失败)
//
// 特点:
// 1. 状态只能改变一次,不能逆转
// 2. pending → fulfilled 或 pending → rejected
// 3. 一旦改变,就固定了(immutable)| 状态 | 含义 | 能否改变 |
|---|---|---|
pending |
进行中,还没结果 | 可以变为 fulfilled 或 rejected |
fulfilled |
已成功,有 resolve 值 | 不可再变 |
rejected |
已失败,有 reject 原因 | 不可再变 |
二、基础方法详解 #
2.1 Promise 的创建 #
// 创建 Promise
const promise = new Promise((resolve, reject) => {
// resolve: 成功时调用,把结果传出去
// reject: 失败时调用,把错误原因传出去
// 模拟异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve('操作成功!'); // 状态变为 fulfilled
} else {
reject('操作失败!'); // 状态变为 rejected
}
}, 1000);
});2.2 then() —— 处理成功结果 #
then() 是 Promise 最核心的方法,用于处理 resolve 的结果。
// then 的完整签名
promise.then(
onFulfilled, // 成功回调,接收 resolve 的值
onRejected // 失败回调(可选),接收 reject 的原因
);
// 示例:基本用法
const p1 = Promise.resolve('成功数据');
p1.then(value => {
console.log('收到:', value); // 输出: 收到: 成功数据
return '处理后的数据'; // 返回值会传给下一个 then
})
.then(value => {
console.log('第二次收到:', value); // 输出: 第二次收到: 处理后的数据
});
// 示例:then 返回新 Promise(链式调用的关键)
const p2 = new Promise(resolve => resolve(10));
p2.then(value => {
console.log('第一次:', value); // 10
return value * 2; // 返回普通值
})
.then(value => {
console.log('第二次:', value); // 20
return new Promise(resolve => resolve(value + 5)); // 返回 Promise
})
.then(value => {
console.log('第三次:', value); // 25
});then 的关键规则:
| 返回值类型 | 下一个 then 收到的值 |
|---|---|
| 普通值(数字、字符串、对象) | 直接收到该值 |
| 新的 Promise | 等这个 Promise resolve 后才收到 |
| 没有 return(undefined) | 收到 undefined |
| throw 抛出错误 | 跳到最近的 catch |
2.3 catch() —— 统一错误处理 #
catch() 是 .then(null, onRejected) 的简写,专门用于捕获错误。
// catch 基本用法
const pError = new Promise((resolve, reject) => {
reject('出错了!');
});
pError
.then(value => console.log('成功:', value)) // 不会执行
.catch(error => console.log('失败:', error)); // 输出: 失败: 出错了!
// catch 捕获链式调用中的所有错误
getUserInfo(userId)
.then(user => getUserOrders(user.id)) // 可能出错
.then(orders => getOrderDetails(orders[0].id)) // 可能出错
.catch(err => console.error('某一步出错了:', err)); // 统一捕获
// catch 后还能继续 then(错误"恢复")
Promise.reject('失败了')
.catch(err => {
console.log('捕获到:', err);
return '恢复后的值'; // catch 返回值可以继续传递
})
.then(value => {
console.log('继续执行:', value); // 输出: 继续执行: 恢复后的值
});2.4 finally() —— 无论成功失败都执行 #
finally() 不关心结果,只关心"结束了"这个事实。常用于清理工作。
// finally 基本用法
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve('数据'), 1000);
});
p
.then(value => console.log('成功:', value))
.catch(error => console.log('失败:', error))
.finally(() => {
console.log('无论成功失败,我都会执行!');
// 常用于:关闭 loading、清理资源、记录日志
});
// 实际场景:关闭 loading
function fetchWithLoading(url) {
showLoading(); // 显示 loading
return fetch(url)
.then(res => res.json())
.catch(err => {
showError(err);
throw err; // 继续抛出,让外部也能捕获
})
.finally(() => {
hideLoading(); // 无论成功失败,都关闭 loading
});
}finally 的特点:
- 不接收任何参数(不知道是成功还是失败)
- 返回值会被忽略(不影响后续链)
- 主要是"清理工作"的场景
三、静态方法详解 #
Promise 类提供了多个静态方法,用于批量处理 Promise。
3.1 Promise.all() —— 全部成功才算成功 #
等待所有 Promise 都成功,返回所有结果的数组。有一个失败就整体失败。
// Promise.all 基本用法
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3])
.then(values => {
console.log(values); // [1, 2, 3]
})
.catch(error => {
console.log('有一个失败了:', error);
});
// 实际场景:并行请求多个接口
function fetchAllData() {
const userPromise = fetch('/api/user').then(r => r.json());
const orderPromise = fetch('/api/orders').then(r => r.json());
const productPromise = fetch('/api/products').then(r => r.json());
return Promise.all([userPromise, orderPromise, productPromise])
.then(([user, orders, products]) => {
return { user, orders, products }; // 三个数据都有了
});
}
// 失败场景:一个失败,整体失败
Promise.all([
Promise.resolve('成功1'),
Promise.reject('失败2'),
Promise.resolve('成功3')
])
.catch(error => {
console.log('整体失败:', error); // 输出: 整体失败: 失败2
// 注意:成功1 和 成功3 的结果丢失了!
});Promise.all 特点总结:
| 情况 | 结果 |
|---|---|
| 全部成功 | 返回所有结果的数组 [v1, v2, v3] |
| 有一个失败 | 立即 reject,返回第一个失败的原因 |
| 顺序 | 结果顺序与传入顺序一致(不管谁先完成) |
3.2 Promise.race() —— 第一个完成就返回 #
返回第一个完成(无论成功失败)的 Promise 结果。
// Promise.race 基本用法
const p1 = new Promise(resolve => setTimeout(() => resolve('慢'), 300));
const p2 = new Promise(resolve => setTimeout(() => resolve('快'), 100));
Promise.race([p1, p2])
.then(value => console.log(value)); // 输出: 快
// 实际场景:请求超时控制
function fetchWithTimeout(url, timeout = 5000) {
const fetchPromise = fetch(url).then(r => r.json());
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), timeout)
);
return Promise.race([fetchPromise, timeoutPromise]);
}
// 使用
fetchWithTimeout('/api/data', 3000)
.then(data => console.log(data))
.catch(err => console.log(err.message)); // 可能输出: 请求超时
// race 也会捕获第一个失败
Promise.race([
Promise.reject('立即失败'),
Promise.resolve('稍后成功')
])
.catch(err => console.log(err)); // 输出: 立即失败3.3 Promise.allSettled() —— 等待所有完成(ES2020) #
等待所有 Promise 完成(无论成功失败),返回每个 Promise 的状态和结果。
// Promise.allSettled 基本用法
const p1 = Promise.resolve('成功1');
const p2 = Promise.reject('失败2');
const p3 = Promise.resolve('成功3');
Promise.allSettled([p1, p2, p3])
.then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: '成功1' },
// { status: 'rejected', reason: '失败2' },
// { status: 'fulfilled', value: '成功3' }
// ]
});
// 实际场景:批量请求,想知道哪些成功哪些失败
function fetchMultipleUrls(urls) {
const promises = urls.map(url =>
fetch(url).then(r => r.json()).catch(err => ({ error: err.message }))
);
return Promise.allSettled(promises)
.then(results => {
const succeeded = results.filter(r => r.status === 'fulfilled');
const failed = results.filter(r => r.status === 'rejected');
console.log(`成功 ${succeeded.length} 个,失败 ${failed.length} 个`);
return { succeeded, failed };
});
}allSettled vs all 对比:
| 方法 | 一个失败时 | 返回值格式 |
|---|---|---|
Promise.all |
整体失败,丢失其他结果 | 直接值 [v1, v2, v3] |
Promise.allSettled |
继续等待其他完成 | { status, value/reason }[] |
3.4 Promise.any() —— 第一个成功就返回(ES2021) #
等待第一个成功,如果全部失败才整体失败。
// Promise.any 基本用法
const p1 = Promise.reject('失败1');
const p2 = Promise.resolve('成功2');
const p3 = Promise.reject('失败3');
Promise.any([p1, p2, p3])
.then(value => console.log(value)); // 输出: 成功2
// 全部失败时
Promise.any([
Promise.reject('失败1'),
Promise.reject('失败2')
])
.catch(error => {
console.log(error); // AggregateError: All promises were rejected
console.log(error.errors); // ['失败1', '失败2']
});
// 实际场景:尝试多个镜像源,取最快成功的
function fetchFromMirrors(url) {
const mirrors = [
'https://mirror1.com',
'https://mirror2.com',
'https://mirror3.com'
];
const promises = mirrors.map(mirror =>
fetch(`${mirror}${url}`).then(r => r.json())
);
return Promise.any(promises)
.then(data => data)
.catch(err => {
console.log('所有镜像都失败了:', err.errors);
});
}3.5 Promise.resolve() / Promise.reject() —— 快捷创建 #
// Promise.resolve —— 创建一个立即成功的 Promise
const p1 = Promise.resolve('数据');
p1.then(value => console.log(value)); // 输出: 数据
// 等价于
const p2 = new Promise(resolve => resolve('数据'));
// Promise.reject —— 创建一个立即失败的 Promise
const p3 = Promise.reject('错误');
p3.catch(error => console.log(error)); // 输出: 错误
// 注意:resolve 如果传入 Promise,会"穿透"
const innerPromise = new Promise(resolve => resolve('内部数据'));
const outerPromise = Promise.resolve(innerPromise);
outerPromise.then(value => console.log(value)); // 输出: 内部数据
// 不是输出 innerPromise 对象!四、静态方法对比速查表 #
| 方法 | 等待策略 | 成功条件 | 失败条件 | 返回值 |
|---|---|---|---|---|
Promise.all |
全部完成 | 全部成功 | 一个失败 | 成功值数组 |
Promise.race |
第一个完成 | 第一个成功 | 第一个失败 | 第一个结果 |
Promise.allSettled |
全部完成 | 不区分 | 不区分 | 状态数组 |
Promise.any |
第一个成功 | 一个成功 | 全部失败 | 第一个成功值 |
选择建议:
| 场景 | 推荐方法 |
|---|---|
| 批量请求,全部成功才算成功 | Promise.all |
| 请求超时控制 | Promise.race |
| 批量请求,想知道每条结果 | Promise.allSettled |
| 多个镜像源,取最快成功的 | Promise.any |
五、手写 Promise 实现 #
5.1 手写 Promise 核心类 #
class MyPromise {
// 三种状态常量
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
// 初始状态
this.status = MyPromise.PENDING;
this.value = undefined; // 成功的值
this.reason = undefined; // 失败的原因
// 回调队列(因为可能 then 在 resolve 之前调用)
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
// resolve 函数
const resolve = (value) => {
// 只能改变一次
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.FULFILLED;
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(cb => cb(this.value));
}
};
// reject 函数
const reject = (reason) => {
if (this.status === MyPromise.PENDING) {
this.status = MyPromise.REJECTED;
this.reason = reason;
// 执行所有失败回调
this.onRejectedCallbacks.forEach(cb => cb(this.reason));
}
};
// 立即执行 executor(可能抛出错误)
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
// then 方法
then(onFulfilled, onRejected) {
// 参数校验:如果不是函数,就穿透传值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回新 Promise(链式调用的关键)
const promise2 = new MyPromise((resolve, reject) => {
// 成功状态 —— 立即执行
if (this.status === MyPromise.FULFILLED) {
// 异步执行(模拟微任务)
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 处理返回值(可能是 Promise)
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 失败状态 —— 立即执行
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// pending 状态 —— 存入队列(异步执行时再调用)
if (this.status === MyPromise.PENDING) {
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
const x = onFulfilled(value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push((reason) => {
setTimeout(() => {
try {
const x = onRejected(reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
// 处理返回值(Promise A+ 规范的核心)
resolvePromise(promise2, x, resolve, reject) {
// 循环引用检测
if (promise2 === x) {
return reject(new TypeError('循环引用'));
}
// x 是 Promise
if (x instanceof MyPromise) {
x.then(
value => this.resolvePromise(promise2, value, resolve, reject),
reject
);
}
// x 是对象或函数(可能有 then 方法)
else if (typeof x === 'object' && x !== null || typeof x === 'function') {
let then;
try {
then = x.then;
} catch (error) {
return reject(error);
}
// 如果 then 是函数,认为是 Promise-like
if (typeof then === 'function') {
let called = false; // 防止多次调用
try {
then.call(
x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} catch (error) {
if (called) return;
reject(error);
}
} else {
resolve(x); // 普通对象
}
}
// x 是普通值
else {
resolve(x);
}
}
// catch 方法
catch(onRejected) {
return this.then(undefined, onRejected);
}
// finally 方法
finally(onFinally) {
return this.then(
value => {
onFinally();
return value;
},
reason => {
onFinally();
throw reason;
}
);
}
// 静态方法:resolve
static resolve(value) {
// 如果已经是 Promise,直接返回
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => resolve(value));
}
// 静态方法:reject
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
}
// 测试 MyPromise
const p = new MyPromise((resolve, reject) => {
setTimeout(() => resolve(10), 100);
});
p.then(value => {
console.log('第一次:', value); // 10
return value * 2;
})
.then(value => {
console.log('第二次:', value); // 20
return new MyPromise(resolve => resolve(value + 5));
})
.then(value => {
console.log('第三次:', value); // 25
})
.catch(err => {
console.log('错误:', err);
});5.2 手写 Promise.all() #
// 手写 Promise.all
MyPromise.all = function(promises) {
return new MyPromise((resolve, reject) => {
// 输入校验
if (!Array.isArray(promises)) {
return reject(new TypeError('promises must be an array'));
}
const results = [];
let completedCount = 0;
const total = promises.length;
// 空数组直接返回空数组
if (total === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
// 确保每个元素都是 Promise
MyPromise.resolve(promise).then(
(value) => {
results[index] = value; // 保持顺序
completedCount++;
// 全部完成
if (completedCount === total) {
resolve(results);
}
},
(reason) => {
reject(reason); // 一个失败,整体失败
}
);
});
});
};
// 测试
MyPromise.all([
MyPromise.resolve(1),
MyPromise.resolve(2),
MyPromise.resolve(3)
])
.then(values => console.log('all 结果:', values)); // [1, 2, 3]5.3 手写 Promise.race() #
// 手写 Promise.race
MyPromise.race = function(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('promises must be an array'));
}
// 空数组永远 pending(标准行为)
if (promises.length === 0) {
return; // 永不 resolve 或 reject
}
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject); // 第一个完成就返回
});
});
};
// 测试
MyPromise.race([
new MyPromise(resolve => setTimeout(() => resolve('慢'), 300)),
new MyPromise(resolve => setTimeout(() => resolve('快'), 100))
])
.then(value => console.log('race 结果:', value)); // 快5.4 手写 Promise.allSettled() #
// 手写 Promise.allSettled
MyPromise.allSettled = function(promises) {
return new MyPromise((resolve) => {
if (!Array.isArray(promises)) {
return resolve([]); // 按标准,返回空数组
}
const results = [];
let settledCount = 0;
const total = promises.length;
if (total === 0) {
return resolve(results);
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
(value) => {
results[index] = { status: 'fulfilled', value };
settledCount++;
if (settledCount === total) {
resolve(results);
}
},
(reason) => {
results[index] = { status: 'rejected', reason };
settledCount++;
if (settledCount === total) {
resolve(results);
}
}
);
});
});
};
// 测试
MyPromise.allSettled([
MyPromise.resolve('成功'),
MyPromise.reject('失败')
])
.then(results => console.log('allSettled 结果:', results));
// [{ status: 'fulfilled', value: '成功' }, { status: 'rejected', reason: '失败' }]5.5 手写 Promise.any() #
// 手写 Promise.any
MyPromise.any = function(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('promises must be an array'));
}
const errors = [];
let rejectedCount = 0;
const total = promises.length;
// 空数组直接 reject
if (total === 0) {
return reject(new AggregateError([], 'All promises were rejected'));
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
resolve, // 第一个成功就直接返回
(reason) => {
errors[index] = reason;
rejectedCount++;
// 全部失败
if (rejectedCount === total) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
};
// AggregateError 类(如果环境不支持)
class AggregateError extends Error {
constructor(errors, message) {
super(message);
this.errors = errors;
this.name = 'AggregateError';
}
}
// 测试
MyPromise.any([
MyPromise.reject('失败1'),
MyPromise.resolve('成功2'),
MyPromise.reject('失败3')
])
.then(value => console.log('any 结果:', value)); // 成功2六、常见问题与陷阱 #
Q1: then 的返回值是什么? #
// then 总是返回一个新的 Promise
const p1 = new Promise(resolve => resolve(1));
const p2 = p1.then(value => value + 1);
console.log(p1 === p2); // false,是两个不同的 Promise
// 这就是链式调用的原理
p1.then(v1 => v1 + 1)
.then(v2 => v2 * 2) // 这是新 Promise 的 then
.then(v3 => console.log(v3));Q2: Promise 和 async/await 的关系? #
async/await 是 Promise 的语法糖,本质还是 Promise。
// async/await 写法
async function fetchData() {
try {
const user = await getUserInfo(userId);
const orders = await getUserOrders(user.id);
return orders;
} catch (error) {
console.error(error);
}
}
// 等价的 Promise 写法
function fetchData() {
return getUserInfo(userId)
.then(user => getUserOrders(user.id))
.catch(error => console.error(error));
}
// async 函数返回 Promise
async function hello() {
return 'hello';
}
hello().then(value => console.log(value)); // helloQ3: Promise 的错误会"吞掉"吗? #
// 未捕获的 Promise 错误不会中断程序,但会静默失败
const p = Promise.reject('错误');
// 没有 catch,程序继续运行,但会有警告
// 最佳实践:总是添加 catch
Promise.reject('错误')
.catch(err => console.error(err));
// 或使用 unhandledrejection 事件(全局捕获)
window.addEventListener('unhandledrejection', event => {
console.error('未捕获的 Promise 错误:', event.reason);
});Q4: 如何让 Promise 可以取消? #
// Promise 本身不能取消,但可以用 race 模拟
function makeCancelable(promise) {
let canceled = false;
const cancelPromise = new Promise((_, reject) => {
setTimeout(() => {
if (canceled) {
reject(new Error('已取消'));
}
}, 0);
});
return {
promise: Promise.race([promise, cancelPromise]),
cancel() {
canceled = true;
}
};
}
// 使用
const { promise, cancel } = makeCancelable(fetch('/api/data'));
promise.then(data => console.log(data)).catch(err => console.log(err));
cancel(); // 手动取消Q5: Promise 执行顺序是怎样的? #
console.log('1. 同步开始');
const p = new Promise(resolve => {
console.log('2. Promise executor(同步执行)');
resolve();
});
p.then(() => {
console.log('4. then 回调(微任务)');
});
console.log('3. 同步结束');
// 输出顺序:1 → 2 → 3 → 4
// executor 是同步执行的!then 回调是微任务(异步)七、总结速记 #
核心方法速查 #
| 方法 | 作用 | 返回值 |
|---|---|---|
then(onFulfilled, onRejected) |
处理结果 | 新 Promise |
catch(onRejected) |
捕获错误 | 新 Promise |
finally(onFinally) |
清理工作 | 新 Promise |
静态方法速查 #
| 方法 | 等待策略 | 成功返回 | 失败返回 |
|---|---|---|---|
Promise.all |
全部完成 | [v1, v2...] |
第一个错误 |
Promise.race |
第一个完成 | 第一个值 | 第一个错误 |
Promise.allSettled |
全部完成 | [{status, value/reason}...] |
不会失败 |
Promise.any |
第一个成功 | 第一个成功值 | AggregateError |
手写 Promise 核心要点 #
- 三种状态:pending、fulfilled、rejected,只能改一次
- 回调队列:then 可能先于 resolve 调用,需要存队列
- 链式调用:then 返回新 Promise,resolvePromise 处理返回值
- 异步执行:回调用 setTimeout 模拟微任务
- 循环引用检测:防止
promise.then(() => promise)歪死循环
最佳实践 #
| 场景 | 建议 |
|---|---|
| 所有 Promise | 一定要有 .catch() |
| 批量请求 | 用 Promise.all 或 Promise.allSettled |
| 超时控制 | 用 Promise.race |
| 清理工作 | 用 .finally() |
| 复杂异步流 | 用 async/await 更清晰 |
附录:完整代码仓库 #
本文所有代码示例均可直接运行,建议创建测试文件实践:
// test-promise.js
// 复制上述手写代码,运行测试
// 运行
node test-promise.js最后更新:2026-03-31