Promise从零到精通:全面掌握JavaScript异步编程核心
/ ✅ 1. 总是返回 Promise// 返回 Promise// ✅ 2. 使用链式调用,避免嵌套getData()// ✅ 3. 总是添加错误处理promise// ✅ 4. 优先使用 async/awaittry {cleanup();// ✅ 5. 并行执行独立的异步操作]);// ✅ 6. 使用有意义的变量名// 不好// 好// ✅ 7. 避免过长的 Promise 链// 不好fe
📚 目录
- Promise 是什么?为什么需要它?
- Promise 的三种状态
- Promise 基础用法
- Promise 的核心方法
- Promise 的静态方法详解
- Promise 链式调用深度解析
- Promise 的错误处理机制
- Promise 与事件循环(微任务机制)
- async/await:Promise 的语法糖
- Promise 实战应用场景
- Promise 常见陷阱与最佳实践
- 手写 Promise(深入理解原理)
- 总结与知识图谱
1. Promise 是什么?为什么需要它?
1.1 JavaScript 的异步问题
在 JavaScript 中,很多操作是异步的,比如:
- 网络请求(Ajax、Fetch)
- 定时器(setTimeout、setInterval)
- 文件读写(Node.js)
- 数据库操作
异步操作的特点:不会立即返回结果,需要等待一段时间。
1.2 回调地狱(Callback Hell)
在 Promise 出现之前,我们使用回调函数来处理异步操作:
// 传统回调方式:层层嵌套,难以维护
getUserInfo(userId, function(user) {
getOrders(user.id, function(orders) {
getOrderDetail(orders[0].id, function(detail) {
getProductInfo(detail.productId, function(product) {
console.log('最终获取到商品信息:', product);
// 如果还有更多异步操作...继续嵌套...
});
});
});
});
回调地狱的问题:
- ❌ 代码横向发展,可读性差(“厄运金字塔”)
- ❌ 错误处理困难,每层都要处理错误
- ❌ 难以维护和调试
- ❌ 无法使用 try-catch 捕获错误
1.3 Promise 的解决方案
Promise 是一种异步编程的解决方案,让异步代码看起来更像同步代码:
// 使用 Promise:链式调用,清晰优雅
getUserInfo(userId)
.then(user => getOrders(user.id))
.then(orders => getOrderDetail(orders[0].id))
.then(detail => getProductInfo(detail.productId))
.then(product => {
console.log('最终获取到商品信息:', product);
})
.catch(error => {
console.error('任何一步出错都会被捕获:', error);
});
Promise 的优势:
- ✅ 链式调用,代码扁平化
- ✅ 统一的错误处理
- ✅ 更好的语义和可读性
- ✅ 方便组合多个异步操作
1.4 Promise 的本质
Promise 是一个承诺:我现在不知道结果,但我承诺未来会给你一个结果(成功或失败)。
// 形象理解:去餐厅点餐
// 1. 你点了一份餐(创建 Promise)
// 2. 服务员给你一个号码牌(Promise 对象)
// 3. 你可以先坐下等待(继续执行其他代码)
// 4. 餐做好了会叫你的号(Promise 状态改变,执行回调)
// - 成功:你拿到了餐(fulfilled)
// - 失败:餐卖完了(rejected)
2. Promise 的三种状态
Promise 对象有且只有三种状态:
2.1 三种状态详解
// 1. pending(进行中):初始状态,既没有成功也没有失败
const promise1 = new Promise((resolve, reject) => {
// 此时 Promise 处于 pending 状态
console.log('正在执行异步操作...');
});
// 2. fulfilled(已成功):操作成功完成
const promise2 = new Promise((resolve, reject) => {
resolve('成功的结果'); // 调用 resolve,状态变为 fulfilled
});
// 3. rejected(已失败):操作失败
const promise3 = new Promise((resolve, reject) => {
reject('失败的原因'); // 调用 reject,状态变为 rejected
});
2.2 状态转换规则
pending ──resolve──> fulfilled(成功)
│
└──reject──> rejected(失败)
重要特性:
- ✅ 状态只能从
pending变为fulfilled或rejected - ✅ 状态一旦改变,就永久保持,不会再变(状态凝固)
- ✅ 状态改变只有两种可能:
pending→fulfilledpending→rejected
2.3 状态不可逆示例
const promise = new Promise((resolve, reject) => {
resolve('成功了');
reject('失败了'); // 这行不会执行,状态已经凝固
resolve('再次成功'); // 这行也不会执行
});
promise.then(
value => console.log(value), // 输出:成功了
reason => console.log(reason) // 不会执行
);
3. Promise 基础用法
3.1 创建 Promise
// 语法:new Promise(executor)
// executor:执行器函数,立即同步执行
const promise = new Promise((resolve, reject) => {
// resolve:成功时调用的函数
// reject:失败时调用的函数
// 模拟异步操作
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('操作成功!'); // 将结果传递给 then
} else {
reject('操作失败!'); // 将错误传递给 catch
}
}, 1000);
});
console.log('Promise 已创建'); // 这行会立即执行
关键点:
new Promise()的参数是一个执行器函数- 执行器函数立即同步执行
- 执行器函数接收两个参数:
resolve和reject
3.2 使用 then() 方法
// then() 方法接收两个参数:成功回调和失败回调
promise.then(
// 参数1:成功回调(可选)
value => {
console.log('成功:', value);
},
// 参数2:失败回调(可选)
reason => {
console.log('失败:', reason);
}
);
3.3 使用 catch() 方法
// catch() 专门用于捕获错误,等价于 .then(null, onRejected)
promise
.then(value => {
console.log('成功:', value);
})
.catch(reason => {
console.log('失败:', reason);
});
3.4 使用 finally() 方法
// finally() 无论成功还是失败都会执行
promise
.then(value => {
console.log('成功:', value);
})
.catch(reason => {
console.log('失败:', reason);
})
.finally(() => {
console.log('无论成功失败,我都会执行');
// 常用于:关闭加载状态、清理资源等
});
3.5 完整示例:模拟网络请求
// 模拟一个网络请求函数
function fetchUser(userId) {
return new Promise((resolve, reject) => {
console.log('开始请求用户数据...');
// 模拟网络延迟
setTimeout(() => {
if (userId > 0) {
resolve({
id: userId,
name: '张三',
age: 25
});
} else {
reject('用户ID无效');
}
}, 1000);
});
}
// 使用
fetchUser(1)
.then(user => {
console.log('用户数据:', user);
// 输出:用户数据: { id: 1, name: '张三', age: 25 }
})
.catch(error => {
console.error('请求失败:', error);
})
.finally(() => {
console.log('请求结束');
});
4. Promise 的核心方法
4.1 then() 方法详解
then() 是 Promise 最核心的方法,它的完整签名是:
promise.then(onFulfilled, onRejected)
关键特性:
- ✅
then()方法返回一个新的 Promise - ✅ 支持链式调用
- ✅ 可以传递值到下一个
then()
// 示例:then() 的返回值
const promise = new Promise((resolve) => {
resolve(1);
});
promise
.then(value => {
console.log(value); // 1
return value + 1; // 返回普通值,会被包装成 Promise
})
.then(value => {
console.log(value); // 2
return value + 1;
})
.then(value => {
console.log(value); // 3
});
then() 的四种返回情况:
// 情况1:返回普通值
promise.then(value => {
return 'hello'; // 会被包装成 Promise.resolve('hello')
});
// 情况2:返回 Promise 对象
promise.then(value => {
return new Promise(resolve => {
resolve('world');
});
});
// 情况3:抛出错误
promise.then(value => {
throw new Error('出错了'); // 会被包装成 Promise.reject(Error)
});
// 情况4:不返回值(返回 undefined)
promise.then(value => {
console.log(value);
// 没有 return,默认返回 Promise.resolve(undefined)
});
4.2 catch() 方法详解
catch() 是 then(null, onRejected) 的语法糖:
// 这两种写法完全等价
promise.catch(error => console.error(error));
promise.then(null, error => console.error(error));
catch() 的强大之处:
// catch() 可以捕获之前任何一步的错误
Promise.resolve()
.then(() => {
throw new Error('第1步出错');
})
.then(() => {
console.log('第2步'); // 不会执行
})
.then(() => {
console.log('第3步'); // 不会执行
})
.catch(error => {
console.error('捕获到错误:', error.message);
// 输出:捕获到错误:第1步出错
});
catch() 也返回 Promise:
Promise.reject('错误')
.catch(error => {
console.log('处理错误:', error);
return '错误已修复'; // 返回新值,链条可以继续
})
.then(value => {
console.log('继续执行:', value); // 输出:继续执行:错误已修复
});
4.3 finally() 方法详解
finally() 是 ES2018 引入的方法,特点是:
// finally() 的特点
Promise.resolve('成功')
.finally(() => {
console.log('finally 执行');
// 注意:finally 不接收任何参数
// 无法知道 Promise 是成功还是失败
})
.then(value => {
console.log(value); // 输出:成功
// finally 不会改变 Promise 的值
});
finally() 的典型应用:
function fetchData() {
// 显示加载状态
showLoading();
return fetch('/api/data')
.then(response => response.json())
.then(data => {
// 处理数据
return data;
})
.catch(error => {
// 处理错误
console.error(error);
})
.finally(() => {
// 无论成功还是失败,都隐藏加载状态
hideLoading();
});
}
5. Promise 的静态方法详解
Promise 提供了多个静态方法,用于处理多个 Promise 的组合场景。
5.1 Promise.resolve()
快速创建一个成功的 Promise:
// 方式1:使用 Promise.resolve()
const promise1 = Promise.resolve('成功');
// 方式2:等价写法
const promise2 = new Promise(resolve => {
resolve('成功');
});
// Promise.resolve() 的三种情况
// 情况1:参数是普通值
Promise.resolve('hello').then(value => {
console.log(value); // hello
});
// 情况2:参数是 Promise 对象
const p = new Promise(resolve => resolve('world'));
Promise.resolve(p).then(value => {
console.log(value); // world
});
// 情况3:参数是 thenable 对象(有 then 方法的对象)
const thenable = {
then(resolve, reject) {
resolve('thenable');
}
};
Promise.resolve(thenable).then(value => {
console.log(value); // thenable
});
5.2 Promise.reject()
快速创建一个失败的 Promise:
// 创建失败的 Promise
Promise.reject('错误原因')
.catch(reason => {
console.log(reason); // 错误原因
});
// 注意:Promise.reject() 不会做特殊处理
// 即使参数是 Promise,也会原样传递
const p = Promise.resolve('成功');
Promise.reject(p)
.catch(reason => {
console.log(reason === p); // true
});
5.3 Promise.all()
用途:并发执行多个 Promise,等待所有 Promise 都成功才成功。
// 语法
Promise.all([promise1, promise2, promise3])
特点:
- ✅ 所有 Promise 都成功,返回所有结果的数组
- ❌ 任何一个 Promise 失败,立即返回失败
// 示例:同时请求多个接口
const promise1 = fetch('/api/user');
const promise2 = fetch('/api/orders');
const promise3 = fetch('/api/products');
Promise.all([promise1, promise2, promise3])
.then(([user, orders, products]) => {
console.log('用户信息:', user);
console.log('订单列表:', orders);
console.log('商品列表:', products);
// 三个请求都成功,才会执行这里
})
.catch(error => {
console.error('有请求失败:', error);
// 任何一个请求失败,都会执行这里
});
实用案例:批量上传文件
function uploadFiles(files) {
const uploadPromises = files.map(file => {
return fetch('/api/upload', {
method: 'POST',
body: file
});
});
return Promise.all(uploadPromises)
.then(results => {
console.log('所有文件上传成功', results);
})
.catch(error => {
console.error('有文件上传失败', error);
});
}
5.4 Promise.race()
用途:并发执行多个 Promise,返回最先完成的那个结果(无论成功还是失败)。
// 语法
Promise.race([promise1, promise2, promise3])
特点:
- ⚡ 谁先完成(成功或失败),就返回谁的结果
- ⚡ 其他 Promise 继续执行,但结果被忽略
// 示例:请求超时控制
function fetchWithTimeout(url, timeout) {
const fetchPromise = fetch(url);
const timeoutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('请求超时');
}, timeout);
});
return Promise.race([fetchPromise, timeoutPromise]);
}
// 使用
fetchWithTimeout('/api/data', 3000)
.then(data => console.log('请求成功', data))
.catch(error => console.error('请求失败或超时', error));
实用案例:多个资源竞速
// 从多个镜像服务器请求,使用最快响应的那个
const mirrors = [
'https://mirror1.com/data',
'https://mirror2.com/data',
'https://mirror3.com/data'
];
Promise.race(mirrors.map(url => fetch(url)))
.then(response => response.json())
.then(data => console.log('最快的服务器返回:', data))
.catch(error => console.error('所有服务器都失败了', error));
5.5 Promise.allSettled()
用途:等待所有 Promise 都完成(无论成功还是失败),返回所有结果。
// 语法(ES2020)
Promise.allSettled([promise1, promise2, promise3])
特点:
- ✅ 永远不会 reject
- ✅ 返回每个 Promise 的状态和结果
- ✅ 适合需要知道所有结果的场景
// 示例
const promises = [
Promise.resolve('成功1'),
Promise.reject('失败2'),
Promise.resolve('成功3')
];
Promise.allSettled(promises)
.then(results => {
console.log(results);
/* 输出:
[
{ status: 'fulfilled', value: '成功1' },
{ status: 'rejected', reason: '失败2' },
{ status: 'fulfilled', value: '成功3' }
]
*/
// 可以分别处理成功和失败的情况
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
实用案例:批量操作统计
async function batchDeleteUsers(userIds) {
const deletePromises = userIds.map(id =>
fetch(`/api/users/${id}`, { method: 'DELETE' })
);
const results = await Promise.allSettled(deletePromises);
const success = results.filter(r => r.status === 'fulfilled').length;
const failed = results.filter(r => r.status === 'rejected').length;
console.log(`删除完成:成功 ${success} 个,失败 ${failed} 个`);
return results;
}
5.6 Promise.any()
用途:只要有一个 Promise 成功就返回,所有 Promise 都失败才失败。
// 语法(ES2021)
Promise.any([promise1, promise2, promise3])
特点:
- ✅ 返回第一个成功的 Promise 结果
- ❌ 所有 Promise 都失败,返回 AggregateError
// 示例
const promises = [
Promise.reject('失败1'),
Promise.resolve('成功2'),
Promise.resolve('成功3')
];
Promise.any(promises)
.then(value => {
console.log(value); // 成功2(第一个成功的)
})
.catch(error => {
console.error('所有 Promise 都失败了', error);
});
实用案例:容错请求
// 尝试从多个备用服务器获取数据
function fetchFromBackup(endpoints) {
const promises = endpoints.map(url => fetch(url));
return Promise.any(promises)
.then(response => response.json())
.catch(error => {
throw new Error('所有服务器都不可用');
});
}
// 使用
fetchFromBackup([
'https://primary.com/api',
'https://backup1.com/api',
'https://backup2.com/api'
])
.then(data => console.log('成功获取数据:', data))
.catch(error => console.error(error));
5.7 静态方法对比表
| 方法 | 用途 | 成功条件 | 失败条件 | 返回值 |
|---|---|---|---|---|
Promise.all() |
全部成功 | 所有成功 | 任一失败 | 所有结果数组 |
Promise.race() |
竞速 | 最先完成的 | 最先完成的 | 第一个完成的结果 |
Promise.allSettled() |
等待全部完成 | 全部完成 | 不会失败 | 所有结果状态数组 |
Promise.any() |
任一成功 | 任一成功 | 全部失败 | 第一个成功的结果 |
6. Promise 链式调用深度解析
6.1 链式调用的原理
核心原理:每个 then() 方法都返回一个新的 Promise。
// 链式调用示例
const promise = new Promise(resolve => {
resolve(1);
});
const promise2 = promise.then(value => {
console.log(value); // 1
return value + 1;
});
const promise3 = promise2.then(value => {
console.log(value); // 2
return value + 1;
});
const promise4 = promise3.then(value => {
console.log(value); // 3
});
// promise !== promise2 !== promise3 !== promise4
// 每个 then() 都返回新的 Promise
6.2 值的传递规则
// 规则1:返回普通值,传递给下一个 then
Promise.resolve(1)
.then(value => value + 1) // 返回 2
.then(value => value * 2) // 接收 2,返回 4
.then(value => {
console.log(value); // 4
});
// 规则2:返回 Promise,等待该 Promise 完成
Promise.resolve(1)
.then(value => {
return new Promise(resolve => {
setTimeout(() => {
resolve(value + 1);
}, 1000);
});
})
.then(value => {
console.log(value); // 1秒后输出 2
});
// 规则3:不返回值,传递 undefined
Promise.resolve(1)
.then(value => {
console.log(value); // 1
// 没有 return
})
.then(value => {
console.log(value); // undefined
});
// 规则4:抛出错误,传递给 catch
Promise.resolve(1)
.then(value => {
throw new Error('出错了');
})
.then(value => {
console.log('不会执行');
})
.catch(error => {
console.error(error.message); // 出错了
});
6.3 链式调用的实际应用
场景1:多步骤数据处理
// 获取用户信息 → 获取订单 → 获取订单详情 → 处理数据
function getUserOrderDetail(userId) {
return fetchUser(userId)
.then(user => {
console.log('1. 获取用户:', user.name);
return fetchOrders(user.id);
})
.then(orders => {
console.log('2. 获取订单列表:', orders.length, '条');
return fetchOrderDetail(orders[0].id);
})
.then(detail => {
console.log('3. 获取订单详情:', detail);
return {
orderId: detail.id,
total: detail.price * detail.quantity
};
})
.then(result => {
console.log('4. 最终结果:', result);
return result;
})
.catch(error => {
console.error('任何步骤出错都会被捕获:', error);
});
}
场景2:条件分支
function processOrder(orderId) {
return fetchOrder(orderId)
.then(order => {
if (order.status === 'paid') {
// 已支付,发货
return shipOrder(order.id);
} else {
// 未支付,发送提醒
return sendPaymentReminder(order.id);
}
})
.then(result => {
console.log('处理完成:', result);
})
.catch(error => {
console.error('处理失败:', error);
});
}
6.4 链式调用的中断
// 如何在中途中断 Promise 链?
function processData(data) {
return validateData(data)
.then(validData => {
if (!validData.isValid) {
// 返回一个 rejected Promise 来中断链条
return Promise.reject('数据验证失败');
}
return saveData(validData);
})
.then(savedData => {
console.log('数据保存成功');
return notifyUser(savedData);
})
.catch(error => {
console.error('中断原因:', error);
});
}
7. Promise 的错误处理机制
7.1 错误的产生方式
Promise 中的错误有两种产生方式:
// 方式1:调用 reject()
const promise1 = new Promise((resolve, reject) => {
reject('主动拒绝');
});
// 方式2:抛出异常
const promise2 = new Promise((resolve, reject) => {
throw new Error('抛出错误');
});
// 这两种方式效果相同
promise1.catch(error => console.log(error)); // 主动拒绝
promise2.catch(error => console.log(error.message)); // 抛出错误
7.2 错误的捕获方式
// 方式1:then 的第二个参数
promise.then(
value => console.log(value),
error => console.error('方式1捕获:', error)
);
// 方式2:catch 方法(推荐)
promise
.then(value => console.log(value))
.catch(error => console.error('方式2捕获:', error));
两种方式的区别:
// 区别:catch 可以捕获 then 中的错误
promise
.then(value => {
throw new Error('then 中的错误');
}, error => {
// 无法捕获 then 回调中的错误
console.error('捕获不到');
});
promise
.then(value => {
throw new Error('then 中的错误');
})
.catch(error => {
// 可以捕获 then 回调中的错误
console.error('可以捕获到:', error.message);
});
7.3 错误的传播机制
// 错误会一直传播,直到被 catch 捕获
Promise.resolve()
.then(() => {
throw new Error('第1步出错');
})
.then(() => {
console.log('第2步:不会执行');
})
.then(() => {
console.log('第3步:不会执行');
})
.catch(error => {
console.error('捕获到错误:', error.message);
// 错误被处理,链条可以继续
return '错误已修复';
})
.then(value => {
console.log('第4步:继续执行', value);
});
7.4 错误恢复机制
// catch 后返回值,链条可以恢复正常流程
function fetchWithRetry(url, retries = 3) {
return fetch(url)
.catch(error => {
if (retries > 0) {
console.log(`请求失败,剩余重试次数:${retries}`);
// 返回新的 Promise,继续重试
return fetchWithRetry(url, retries - 1);
}
// 重试次数用完,抛出错误
throw error;
});
}
7.5 未捕获的错误
// ⚠️ 如果错误没有被捕获,会产生 UnhandledPromiseRejection
const promise = new Promise((resolve, reject) => {
reject('未处理的错误');
});
// 浏览器会报警告:Uncaught (in promise) 未处理的错误
// Node.js 会发出 unhandledRejection 事件
// 全局捕获未处理的 Promise 错误(浏览器)
window.addEventListener('unhandledrejection', event => {
console.error('未处理的 Promise 错误:', event.reason);
event.preventDefault(); // 阻止默认行为
});
// 全局捕获未处理的 Promise 错误(Node.js)
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的 Promise 错误:', reason);
});
7.6 错误处理最佳实践
// ✅ 推荐:总是在 Promise 链的末尾添加 catch
fetchData()
.then(processData)
.then(saveData)
.catch(error => {
// 统一错误处理
console.error('操作失败:', error);
// 可以根据错误类型做不同处理
if (error.name === 'NetworkError') {
showErrorMessage('网络错误,请检查网络连接');
} else if (error.name === 'ValidationError') {
showErrorMessage('数据验证失败');
} else {
showErrorMessage('未知错误');
}
})
.finally(() => {
// 清理工作
hideLoading();
});
// ❌ 不推荐:忘记添加 catch
fetchData()
.then(processData)
.then(saveData); // 可能产生未捕获的错误
8. Promise 与事件循环(微任务机制)
8.1 事件循环基础
JavaScript 是单线程语言,通过**事件循环(Event Loop)**来处理异步任务。
事件循环的执行顺序:
- 执行同步代码(宏任务)
- 清空微任务队列
- 执行下一个宏任务
- 重复步骤 2-3
┌─────────────────────────────┐
│ 执行同步代码(宏任务) │
└──────────────┬──────────────┘
│
↓
┌─────────────────────────────┐
│ 清空所有微任务队列 │ ← Promise.then/catch/finally
└──────────────┬──────────────┘
│
↓
┌─────────────────────────────┐
│ 执行下一个宏任务 │ ← setTimeout/setInterval
└──────────────┬──────────────┘
│
↓ (循环)
8.2 宏任务 vs 微任务
宏任务(Macro Task):
script整体代码setTimeoutsetIntervalsetImmediate(Node.js)- I/O 操作
- UI 渲染
微任务(Micro Task):
Promise.then/catch/finallyMutationObserverprocess.nextTick(Node.js)queueMicrotask
重要规则:
- ✅ 微任务优先级高于宏任务
- ✅ 每执行完一个宏任务,会清空所有微任务
- ✅ Promise 的回调是微任务
8.3 Promise 的执行时机
console.log('1. 同步代码开始');
setTimeout(() => {
console.log('2. setTimeout 宏任务');
}, 0);
Promise.resolve()
.then(() => {
console.log('3. Promise.then 微任务');
});
console.log('4. 同步代码结束');
// 输出顺序:
// 1. 同步代码开始
// 4. 同步代码结束
// 3. Promise.then 微任务
// 2. setTimeout 宏任务
执行过程分析:
- 执行同步代码:输出 1、4
- 同步代码执行完毕,检查微任务队列
- 执行微任务:输出 3
- 微任务清空,执行宏任务:输出 2
8.4 复杂示例分析
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
Promise.resolve()
.then(() => {
console.log('promise1');
})
.then(() => {
console.log('promise2');
});
new Promise((resolve) => {
console.log('promise3');
resolve();
})
.then(() => {
console.log('promise4');
});
console.log('script end');
// 输出顺序:
// script start
// promise3 ← new Promise 的执行器是同步的
// script end
// promise1 ← 第一批微任务
// promise4 ← 第一批微任务
// promise2 ← 第二批微任务(promise1 的 then)
// setTimeout ← 宏任务
8.5 Promise 构造函数是同步的
console.log('1');
const promise = new Promise((resolve) => {
console.log('2'); // ← 立即执行
resolve();
console.log('3'); // ← 立即执行
});
promise.then(() => {
console.log('4'); // ← 微任务
});
console.log('5');
// 输出顺序:1 → 2 → 3 → 5 → 4
关键点:
- ✅
new Promise(executor)中的executor函数是同步执行的 - ✅ 只有
then/catch/finally的回调是微任务
8.6 实战:微任务与宏任务混合
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('3');
});
}, 0);
new Promise((resolve) => {
console.log('4');
resolve();
setTimeout(() => {
console.log('5');
}, 0);
})
.then(() => {
console.log('6');
setTimeout(() => {
console.log('7');
}, 0);
});
console.log('8');
// 输出顺序:1 → 4 → 8 → 6 → 2 → 3 → 5 → 7
分析过程:
- 同步代码:1、4、8
- 微任务队列:6
- 宏任务队列:setTimeout(2)、setTimeout(5)
- 执行微任务:6(同时添加 setTimeout(7))
- 执行宏任务:2(添加微任务 3)
- 清空微任务:3
- 执行宏任务:5、7
9. async/await:Promise 的语法糖
9.1 async/await 基础
async/await 是 ES2017 引入的语法,让异步代码看起来像同步代码。
// Promise 写法
function fetchUser() {
return fetch('/api/user')
.then(response => response.json())
.then(user => {
console.log(user);
return user;
})
.catch(error => {
console.error(error);
});
}
// async/await 写法
async function fetchUser() {
try {
const response = await fetch('/api/user');
const user = await response.json();
console.log(user);
return user;
} catch (error) {
console.error(error);
}
}
9.2 async 函数
async 关键字:
- ✅
async函数总是返回一个 Promise - ✅ 函数内的返回值会被自动包装成 Promise
// 示例1:返回普通值
async function getValue() {
return 'hello';
}
getValue().then(value => {
console.log(value); // hello
});
// 等价于
function getValue() {
return Promise.resolve('hello');
}
// 示例2:返回 Promise
async function getPromise() {
return Promise.resolve('world');
}
getPromise().then(value => {
console.log(value); // world
});
// 示例3:抛出错误
async function throwError() {
throw new Error('出错了');
}
throwError().catch(error => {
console.error(error.message); // 出错了
});
9.3 await 关键字
await 关键字:
- ✅ 只能在
async函数中使用 - ✅ 等待 Promise 完成,返回 fulfilled 的值
- ✅ 如果 Promise rejected,抛出错误
// 示例:await 的使用
async function example() {
// 等待 Promise 完成
const value1 = await Promise.resolve('成功');
console.log(value1); // 成功
// await 也可以用于非 Promise 值
const value2 = await 'hello';
console.log(value2); // hello(立即返回)
// await 后面的代码会等待 Promise 完成后执行
const value3 = await new Promise(resolve => {
setTimeout(() => resolve('延迟1秒'), 1000);
});
console.log(value3); // 1秒后输出:延迟1秒
}
9.4 错误处理
// 方式1:try-catch(推荐)
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('请求失败:', error);
// 可以选择重新抛出或返回默认值
return null;
}
}
// 方式2:catch 方法
async function fetchData() {
const response = await fetch('/api/data').catch(error => {
console.error('请求失败:', error);
return null;
});
if (!response) return null;
const data = await response.json();
return data;
}
// 方式3:统一错误处理
async function fetchData() {
const response = await fetch('/api/data');
const data = await response.json();
return data;
}
// 调用时处理错误
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));
9.5 并发执行
// ❌ 串行执行(慢)
async function sequential() {
const user = await fetchUser(); // 等待1秒
const orders = await fetchOrders(); // 再等待1秒
const products = await fetchProducts(); // 再等待1秒
// 总共需要3秒
return { user, orders, products };
}
// ✅ 并发执行(快)
async function concurrent() {
// 同时发起请求
const [user, orders, products] = await Promise.all([
fetchUser(),
fetchOrders(),
fetchProducts()
]);
// 总共只需要1秒(最慢的那个请求的时间)
return { user, orders, products };
}
// ✅ 更灵活的并发控制
async function flexible() {
// 先发起所有请求
const userPromise = fetchUser();
const ordersPromise = fetchOrders();
const productsPromise = fetchProducts();
// 按需等待
const user = await userPromise;
console.log('用户信息已获取:', user);
const orders = await ordersPromise;
console.log('订单信息已获取:', orders);
const products = await productsPromise;
console.log('商品信息已获取:', products);
return { user, orders, products };
}
9.6 循环中使用 await
// ❌ 在 forEach 中使用 await(不会等待)
async function processItems() {
const items = [1, 2, 3];
items.forEach(async (item) => {
await processItem(item);
console.log('处理完成:', item);
});
console.log('全部完成'); // 这行会先执行!
}
// ✅ 使用 for...of(串行)
async function processItemsSerial() {
const items = [1, 2, 3];
for (const item of items) {
await processItem(item);
console.log('处理完成:', item);
}
console.log('全部完成'); // 确保所有处理完成后执行
}
// ✅ 使用 Promise.all(并行)
async function processItemsParallel() {
const items = [1, 2, 3];
await Promise.all(items.map(item => processItem(item)));
console.log('全部完成');
}
// ✅ 使用 for 循环(串行,更灵活)
async function processItemsFlexible() {
const items = [1, 2, 3];
const results = [];
for (let i = 0; i < items.length; i++) {
const result = await processItem(items[i]);
results.push(result);
console.log(`进度:${i + 1}/${items.length}`);
}
console.log('全部完成', results);
return results;
}
9.7 async/await 与 Promise 对比
// Promise 链式调用
function getUserOrders() {
return fetchUser()
.then(user => fetchOrders(user.id))
.then(orders => {
return orders.filter(order => order.status === 'paid');
})
.catch(error => {
console.error(error);
throw error;
});
}
// async/await 版本
async function getUserOrders() {
try {
const user = await fetchUser();
const orders = await fetchOrders(user.id);
return orders.filter(order => order.status === 'paid');
} catch (error) {
console.error(error);
throw error;
}
}
优势对比:
- ✅ async/await 更接近同步代码的思维方式
- ✅ 错误处理使用熟悉的 try-catch
- ✅ 更容易调试(断点、堆栈跟踪)
- ✅ 代码更简洁,避免回调嵌套
10. Promise 实战应用场景
10.1 网络请求封装
// 封装一个通用的请求函数
function request(url, options = {}) {
return fetch(url, {
method: options.method || 'GET',
headers: {
'Content-Type': 'application/json',
...options.headers
},
body: options.body ? JSON.stringify(options.body) : undefined
})
.then(response => {
// 检查响应状态
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
return response.json();
})
.catch(error => {
console.error('请求失败:', error);
throw error;
});
}
// 使用
request('/api/users')
.then(users => console.log(users))
.catch(error => console.error(error));
// 带超时的请求
function requestWithTimeout(url, options = {}, timeout = 5000) {
return Promise.race([
request(url, options),
new Promise((_, reject) => {
setTimeout(() => reject(new Error('请求超时')), timeout);
})
]);
}
10.2 重试机制
// 实现请求重试
function fetchWithRetry(url, options = {}, maxRetries = 3) {
return fetch(url, options)
.catch(error => {
if (maxRetries <= 0) {
throw error;
}
console.log(`请求失败,重试中... (剩余 ${maxRetries} 次)`);
// 延迟后重试
return new Promise(resolve => {
setTimeout(() => {
resolve(fetchWithRetry(url, options, maxRetries - 1));
}, 1000);
});
});
}
// 使用
fetchWithRetry('/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('重试失败:', error));
// 更高级的重试:指数退避
async function fetchWithExponentialBackoff(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
if (i === maxRetries - 1) throw error;
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s...
console.log(`重试中... ${delay}ms 后重试`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
10.3 并发控制
// 控制并发数量,避免同时发起过多请求
class PromisePool {
constructor(maxConcurrent) {
this.maxConcurrent = maxConcurrent; // 最大并发数
this.currentCount = 0; // 当前并发数
this.queue = []; // 等待队列
}
async add(promiseCreator) {
// 如果达到最大并发数,等待
while (this.currentCount >= this.maxConcurrent) {
await new Promise(resolve => this.queue.push(resolve));
}
// 执行任务
this.currentCount++;
try {
const result = await promiseCreator();
return result;
} finally {
this.currentCount--;
// 从队列中取出下一个任务
const resolve = this.queue.shift();
if (resolve) resolve();
}
}
}
// 使用示例
async function batchFetch(urls) {
const pool = new PromisePool(3); // 最多同时3个请求
const promises = urls.map(url => {
return pool.add(() => fetch(url).then(r => r.json()));
});
return Promise.all(promises);
}
// 测试
const urls = Array.from({ length: 10 }, (_, i) => `/api/data/${i}`);
batchFetch(urls)
.then(results => console.log('所有请求完成:', results))
.catch(error => console.error(error));
10.4 图片预加载
// 预加载单张图片
function preloadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`图片加载失败: ${url}`));
img.src = url;
});
}
// 批量预加载图片
async function preloadImages(urls) {
const results = await Promise.allSettled(
urls.map(url => preloadImage(url))
);
const success = results.filter(r => r.status === 'fulfilled').length;
const failed = results.filter(r => r.status === 'rejected').length;
console.log(`图片加载完成:成功 ${success} 张,失败 ${failed} 张`);
return results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
}
// 使用
const imageUrls = [
'/images/1.jpg',
'/images/2.jpg',
'/images/3.jpg'
];
preloadImages(imageUrls)
.then(images => {
console.log('所有图片已加载:', images);
// 可以开始显示图片
});
10.5 数据缓存
// 带缓存的数据获取
class DataCache {
constructor() {
this.cache = new Map();
this.pendingPromises = new Map();
}
async fetch(key, fetcher, ttl = 60000) {
// 检查缓存
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < ttl) {
console.log('从缓存获取:', key);
return cached.data;
}
// 检查是否有正在进行的请求
if (this.pendingPromises.has(key)) {
console.log('等待正在进行的请求:', key);
return this.pendingPromises.get(key);
}
// 发起新请求
console.log('发起新请求:', key);
const promise = fetcher()
.then(data => {
// 存入缓存
this.cache.set(key, {
data,
timestamp: Date.now()
});
// 移除待处理记录
this.pendingPromises.delete(key);
return data;
})
.catch(error => {
// 移除待处理记录
this.pendingPromises.delete(key);
throw error;
});
// 记录待处理的 Promise
this.pendingPromises.set(key, promise);
return promise;
}
clear(key) {
if (key) {
this.cache.delete(key);
} else {
this.cache.clear();
}
}
}
// 使用
const cache = new DataCache();
function getUser(id) {
return cache.fetch(
`user:${id}`,
() => fetch(`/api/users/${id}`).then(r => r.json()),
30000 // 30秒缓存
);
}
// 多次调用,只会发起一次请求
getUser(1).then(user => console.log('第1次:', user));
getUser(1).then(user => console.log('第2次:', user)); // 使用缓存
getUser(1).then(user => console.log('第3次:', user)); // 使用缓存
10.6 顺序执行
// 顺序执行一组异步任务
function sequentialExecute(tasks) {
return tasks.reduce((promise, task) => {
return promise.then(results => {
return task().then(result => {
return [...results, result];
});
});
}, Promise.resolve([]));
}
// 使用
const tasks = [
() => fetch('/api/step1').then(r => r.json()),
() => fetch('/api/step2').then(r => r.json()),
() => fetch('/api/step3').then(r => r.json())
];
sequentialExecute(tasks)
.then(results => {
console.log('所有步骤完成:', results);
});
// async/await 版本
async function sequentialExecuteAsync(tasks) {
const results = [];
for (const task of tasks) {
const result = await task();
results.push(result);
}
return results;
}
10.7 轮询
// 定时轮询,直到满足条件
function poll(fn, validate, interval = 1000, maxAttempts = 30) {
let attempts = 0;
return new Promise((resolve, reject) => {
const executePoll = async () => {
try {
const result = await fn();
attempts++;
if (validate(result)) {
resolve(result);
} else if (attempts >= maxAttempts) {
reject(new Error('轮询超时'));
} else {
setTimeout(executePoll, interval);
}
} catch (error) {
reject(error);
}
};
executePoll();
});
}
// 使用:轮询订单状态
poll(
() => fetch('/api/order/123').then(r => r.json()),
order => order.status === 'completed',
2000, // 每2秒轮询一次
30 // 最多30次(1分钟)
)
.then(order => console.log('订单完成:', order))
.catch(error => console.error('轮询失败:', error));
11. Promise 常见陷阱与最佳实践
11.1 忘记返回 Promise
// ❌ 错误:忘记返回 Promise
function getUserData() {
fetchUser().then(user => {
return fetchOrders(user.id); // 返回了,但是外层函数没有返回
});
}
getUserData().then(data => {
console.log(data); // undefined
});
// ✅ 正确:返回 Promise
function getUserData() {
return fetchUser().then(user => {
return fetchOrders(user.id);
});
}
getUserData().then(data => {
console.log(data); // 正确的数据
});
11.2 Promise 嵌套
// ❌ 错误:Promise 嵌套(Promise 地狱)
function getData() {
return fetchUser().then(user => {
return fetchOrders(user.id).then(orders => {
return fetchProducts(orders[0].id).then(products => {
return products;
});
});
});
}
// ✅ 正确:链式调用
function getData() {
return fetchUser()
.then(user => fetchOrders(user.id))
.then(orders => fetchProducts(orders[0].id))
.then(products => products);
}
// ✅ 更好:async/await
async function getData() {
const user = await fetchUser();
const orders = await fetchOrders(user.id);
const products = await fetchProducts(orders[0].id);
return products;
}
11.3 忘记错误处理
// ❌ 错误:没有错误处理
fetchUser()
.then(user => console.log(user)); // 如果出错,会产生未捕获的错误
// ✅ 正确:添加 catch
fetchUser()
.then(user => console.log(user))
.catch(error => console.error(error));
// ✅ 或者在调用时处理
async function main() {
try {
const user = await fetchUser();
console.log(user);
} catch (error) {
console.error(error);
}
}
11.4 在循环中创建 Promise
// ❌ 错误:在循环中使用 async/await(串行执行)
async function processUsers(userIds) {
const results = [];
for (const id of userIds) {
const user = await fetchUser(id); // 逐个等待
results.push(user);
}
return results; // 如果有10个用户,每个1秒,总共10秒
}
// ✅ 正确:并行执行
async function processUsers(userIds) {
return Promise.all(userIds.map(id => fetchUser(id)));
// 总共只需要1秒
}
// ✅ 如果需要控制并发数
async function processUsers(userIds) {
const pool = new PromisePool(3);
return Promise.all(
userIds.map(id => pool.add(() => fetchUser(id)))
);
}
11.5 Promise 构造函数反模式
// ❌ 错误:不必要的 Promise 包装
function getUser() {
return new Promise((resolve, reject) => {
fetchUser() // fetchUser 已经返回 Promise
.then(user => resolve(user))
.catch(error => reject(error));
});
}
// ✅ 正确:直接返回 Promise
function getUser() {
return fetchUser();
}
// ❌ 错误:包装 async 函数
function getUser() {
return new Promise(async (resolve, reject) => {
try {
const user = await fetchUser();
resolve(user);
} catch (error) {
reject(error);
}
});
}
// ✅ 正确:直接使用 async 函数
async function getUser() {
return await fetchUser();
}
11.6 then() 中的副作用
// ❌ 不好:在 then 中修改外部变量
let userData;
fetchUser()
.then(user => {
userData = user; // 副作用
});
console.log(userData); // undefined(异步还没完成)
// ✅ 好:使用返回值
fetchUser()
.then(user => {
console.log(user); // 在这里使用数据
return user;
});
// ✅ 或者使用 async/await
async function main() {
const userData = await fetchUser();
console.log(userData); // 确保数据已获取
}
11.7 最佳实践总结
// ✅ 1. 总是返回 Promise
function getData() {
return fetchData(); // 返回 Promise
}
// ✅ 2. 使用链式调用,避免嵌套
getData()
.then(processData)
.then(saveData)
.catch(handleError);
// ✅ 3. 总是添加错误处理
promise
.then(handleSuccess)
.catch(handleError)
.finally(cleanup);
// ✅ 4. 优先使用 async/await
async function main() {
try {
const data = await fetchData();
const processed = await processData(data);
return processed;
} catch (error) {
handleError(error);
} finally {
cleanup();
}
}
// ✅ 5. 并行执行独立的异步操作
async function loadData() {
const [users, orders, products] = await Promise.all([
fetchUsers(),
fetchOrders(),
fetchProducts()
]);
return { users, orders, products };
}
// ✅ 6. 使用有意义的变量名
// 不好
promise.then(d => console.log(d));
// 好
promise.then(userData => console.log(userData));
// ✅ 7. 避免过长的 Promise 链
// 不好
fetch()
.then(r => r.json())
.then(d => process(d))
.then(pd => transform(pd))
.then(td => validate(td))
.then(vd => save(vd))
.then(sd => notify(sd));
// 好:拆分成多个函数
async function processData() {
const response = await fetch();
const data = await response.json();
const processed = await process(data);
const transformed = await transform(processed);
const validated = await validate(transformed);
const saved = await save(validated);
return notify(saved);
}
12. 手写 Promise(深入理解原理)
12.1 Promise/A+ 规范核心要点
Promise/A+ 是 Promise 的标准规范,核心要求:
- Promise 有三个状态:pending、fulfilled、rejected
- 状态只能从 pending 变为 fulfilled 或 rejected
- 状态一旦改变,不能再变
- then 方法返回新的 Promise
- then 方法可以链式调用
12.2 简易版 Promise 实现
// 简易版 Promise 实现(教学用)
class MyPromise {
// 三个状态常量
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor) {
// 初始状态
this.state = MyPromise.PENDING;
// 成功的值
this.value = undefined;
// 失败的原因
this.reason = undefined;
// 成功回调队列
this.onFulfilledCallbacks = [];
// 失败回调队列
this.onRejectedCallbacks = [];
// resolve 函数
const resolve = (value) => {
// 只有 pending 状态才能转换
if (this.state === MyPromise.PENDING) {
this.state = MyPromise.FULFILLED;
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// reject 函数
const reject = (reason) => {
// 只有 pending 状态才能转换
if (this.state === MyPromise.PENDING) {
this.state = MyPromise.REJECTED;
this.reason = reason;
// 执行所有失败回调
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
// 立即执行 executor
executor(resolve, reject);
} catch (error) {
// 如果执行器抛出错误,直接 reject
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) => {
// 如果已经是 fulfilled 状态
if (this.state === MyPromise.FULFILLED) {
// 使用 setTimeout 模拟微任务
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
}, 0);
}
// 如果已经是 rejected 状态
if (this.state === MyPromise.REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
}, 0);
}
// 如果还是 pending 状态,保存回调
if (this.state === MyPromise.PENDING) {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
// catch 方法
catch(onRejected) {
return this.then(null, onRejected);
}
// finally 方法
finally(onFinally) {
return this.then(
value => {
onFinally();
return value;
},
reason => {
onFinally();
throw reason;
}
);
}
// 静态方法:resolve
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise(resolve => {
resolve(value);
});
}
// 静态方法:reject
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
// 静态方法:all
static all(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError('参数必须是数组'));
return;
}
const results = [];
let count = 0;
if (promises.length === 0) {
resolve(results);
return;
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
count++;
if (count === promises.length) {
resolve(results);
}
},
reason => {
reject(reason);
}
);
});
});
}
// 静态方法:race
static race(promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
reject(new TypeError('参数必须是数组'));
return;
}
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
}
12.3 测试手写的 Promise
// 测试1:基本功能
console.log('=== 测试1:基本功能 ===');
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
promise1.then(value => {
console.log('1. Promise resolved:', value);
});
// 测试2:链式调用
console.log('=== 测试2:链式调用 ===');
MyPromise.resolve(1)
.then(value => {
console.log('2. 第1步:', value);
return value + 1;
})
.then(value => {
console.log('2. 第2步:', value);
return value + 1;
})
.then(value => {
console.log('2. 第3步:', value);
});
// 测试3:错误处理
console.log('=== 测试3:错误处理 ===');
MyPromise.reject('错误')
.then(value => {
console.log('不会执行');
})
.catch(reason => {
console.log('3. 捕获错误:', reason);
});
// 测试4:Promise.all
console.log('=== 测试4:Promise.all ===');
MyPromise.all([
MyPromise.resolve(1),
MyPromise.resolve(2),
MyPromise.resolve(3)
])
.then(values => {
console.log('4. Promise.all:', values);
});
// 测试5:Promise.race
console.log('=== 测试5:Promise.race ===');
MyPromise.race([
new MyPromise(resolve => setTimeout(() => resolve('慢'), 2000)),
new MyPromise(resolve => setTimeout(() => resolve('快'), 1000))
])
.then(value => {
console.log('5. Promise.race:', value);
});
12.4 完整版 Promise(处理 Promise 链式返回)
// 完整版需要处理 then 返回 Promise 的情况
class MyPromiseComplete extends MyPromise {
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
const promise2 = new MyPromiseComplete((resolve, reject) => {
const handleFulfilled = () => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 处理返回值
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
};
const handleRejected = () => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
// 处理返回值
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
};
if (this.state === MyPromise.FULFILLED) {
handleFulfilled();
} else if (this.state === MyPromise.REJECTED) {
handleRejected();
} else {
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
return promise2;
}
// 处理 Promise 解析
resolvePromise(promise2, x, resolve, reject) {
// 避免循环引用
if (promise2 === x) {
reject(new TypeError('循环引用'));
return;
}
// 如果 x 是 Promise
if (x instanceof MyPromiseComplete) {
x.then(resolve, reject);
return;
}
// 如果 x 是对象或函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
const then = x.then;
if (typeof then === 'function') {
// 如果 x 有 then 方法,当作 Promise 处理
then.call(x, resolve, reject);
} else {
resolve(x);
}
} catch (error) {
reject(error);
}
} else {
// 普通值
resolve(x);
}
}
}
// 测试循环引用
const p = new MyPromiseComplete(resolve => {
resolve(1);
});
const p2 = p.then(() => {
return p2; // 循环引用
});
p2.catch(error => {
console.log('循环引用错误:', error.message);
});
13. 总结与知识图谱
13.1 Promise 核心知识点
Promise 核心体系
│
├─ 基础概念
│ ├─ 三种状态(pending、fulfilled、rejected)
│ ├─ 状态不可逆
│ └─ 解决回调地狱
│
├─ 核心方法
│ ├─ then() - 链式调用核心
│ ├─ catch() - 错误处理
│ └─ finally()- 清理操作
│
├─ 静态方法
│ ├─ Promise.resolve() - 快速创建成功 Promise
│ ├─ Promise.reject() - 快速创建失败 Promise
│ ├─ Promise.all() - 全部成功才成功
│ ├─ Promise.race() - 竞速,返回最快的
│ ├─ Promise.allSettled() - 等待全部完成
│ └─ Promise.any() - 任一成功即成功
│
├─ 执行机制
│ ├─ 微任务队列
│ ├─ 事件循环
│ └─ 与宏任务的关系
│
├─ 语法糖
│ ├─ async 函数
│ └─ await 关键字
│
└─ 实战应用
├─ 网络请求封装
├─ 重试机制
├─ 并发控制
├─ 超时处理
└─ 错误处理
13.2 Promise 状态转换图
初始状态
↓
pending(进行中)
├─ resolve() ─→ fulfilled(已成功)─┐
│ │
└─ reject() ─→ rejected(已失败) ─┤
│
↓
状态凝固
永不改变
13.3 Promise 方法对比
| 特性 | then | catch | finally |
|---|---|---|---|
| 处理成功 | ✅ | ❌ | ❌ |
| 处理失败 | ✅ | ✅ | ❌ |
| 接收参数 | ✅ | ✅ | ❌ |
| 返回 Promise | ✅ | ✅ | ✅ |
| 改变 Promise 值 | ✅ | ✅ | ❌ |
13.4 Promise 静态方法对比
| 方法 | 输入 | 成功条件 | 失败条件 | 返回值 |
|---|---|---|---|---|
| all | Promise[] | 全部成功 | 任一失败 | 结果数组 |
| race | Promise[] | 最先完成 | 最先完成 | 首个结果 |
| allSettled | Promise[] | 全部完成 | 不会失败 | 状态数组 |
| any | Promise[] | 任一成功 | 全部失败 | 首个成功 |
13.5 最佳实践检查清单
✅ 代码规范
- 总是返回 Promise
- 使用链式调用,避免嵌套
- 优先使用 async/await
- 使用有意义的变量名
✅ 错误处理
- 每个 Promise 链都有 catch
- 使用 try-catch 包裹 await
- 处理未捕获的 Promise 错误
- 记录错误日志
✅ 性能优化
- 并行执行独立的异步操作
- 控制并发数量
- 使用缓存减少重复请求
- 实现请求去重
✅ 代码维护
- 拆分过长的 Promise 链
- 提取可复用的 Promise 函数
- 添加适当的注释
- 编写单元测试
13.6 学习路径建议
第1阶段:基础入门(1-2天)
├─ 理解 Promise 的概念和意义
├─ 掌握三种状态
├─ 学会创建和使用 Promise
└─ 练习 then/catch/finally
第2阶段:深入理解(3-5天)
├─ 理解链式调用原理
├─ 掌握错误处理机制
├─ 学习静态方法
└─ 理解微任务机制
第3阶段:实战应用(1周)
├─ 封装网络请求
├─ 实现重试机制
├─ 处理并发控制
└─ 结合 async/await
第4阶段:高级进阶(1周)
├─ 手写 Promise
├─ 深入事件循环
├─ 性能优化
└─ 阅读源码
13.7 常见问题 FAQ
Q1: Promise 和 async/await 有什么区别?
- async/await 是 Promise 的语法糖
- async 函数返回 Promise
- await 等待 Promise 完成
- async/await 代码更像同步代码,更易读
Q2: 什么时候用 Promise.all,什么时候用 Promise.race?
- Promise.all:需要等待所有结果(如批量请求)
- Promise.race:需要最快的结果(如超时控制)
Q3: 如何取消一个 Promise?
- Promise 本身不支持取消
- 可以使用 AbortController(Fetch API)
- 或者自己实现取消逻辑(包装 Promise)
Q4: Promise 的错误为什么没有被捕获?
- 检查是否添加了 catch
- 检查 catch 的位置(是否在错误发生之后)
- 检查是否使用了 return
Q5: 为什么 Promise 的回调不会立即执行?
- Promise 的回调是微任务
- 微任务在当前宏任务完成后执行
- 这是事件循环的机制
13.8 推荐学习资源
文档
实践
- 在项目中使用 Promise 替代回调
- 尝试手写 Promise
- 阅读优秀开源库的 Promise 使用
- 做 LeetCode 相关题目
🎯 结语
Promise 是现代 JavaScript 异步编程的基石,掌握 Promise 对于前端开发至关重要。
学习建议:
- 先理解概念,再动手实践
- 多写代码,遇到问题多思考
- 阅读优秀的开源代码
- 尝试手写 Promise 加深理解
记住这三个核心:
- 🎯 Promise 是一个状态机(三种状态,不可逆)
- 🎯 then 返回新 Promise(支持链式调用)
- 🎯 错误会向下传播(直到被 catch)
希望这篇文章能帮助你全面掌握 Promise!加油!💪
更多推荐

所有评论(0)