大家好,我是格子,一名在上海一家公司工作5年的前端开发师,这是我首次发布稀土掘金,希望和各位大佬共同学习进步 感谢支持
在现代前端开发中,异步编程几乎是家常便饭。而 Promise.all
作为 JavaScript 中最强大的异步工具之一,能够帮助我们优雅地处理多个 Promise 的并发执行。但你知道它的真正威力吗?本文将带你深入挖掘 Promise.all
的 10 个实用技巧,让你的代码更简洁、更高效!
🔍 什么是 Promise.all
?
简单来说,Promise.all(iterable)
接收一个 Promise 可迭代对象(如数组),并返回一个新的 Promise。当所有输入的 Promise 都成功完成时,它才会 resolve,并返回一个数组,包含每个 Promise 的结果;只要有一个 Promise 被 reject,它就会立即 reject。
ini
const p1 = Promise.resolve(3);
const p2 = new Promise((resolve, reject) => setTimeout(reject, 100, '出错了'));
const p3 = fetch('https://api.example.com/data');
Promise.all([p1, p2, p3])
.then(values => console.log(values))
.catch(error => console.error(error));
✨ 10 个你必须掌握的 Promise.all
技巧
1. 并发请求数据,提升性能
当你需要从多个 API 获取数据时,使用 Promise.all
可以并发执行请求,而不是串行等待:
javascript
const [userRes, productRes] = await Promise.all([
fetch('/api/users'),
fetch('/api/products')
]);
⚠️ 注意:确保后端支持并发请求,避免造成服务器压力过大。
2. 捕获错误,防止中断
默认情况下,任何一个 Promise 被 reject,整个 Promise.all
就会失败。如果你希望即使有失败也能继续执行其他请求,可以结合 .catch()
使用:
dart
const results = await Promise.all([
fetchData1().catch(err => null),
fetchData2().catch(err => null)
]);
这样即使某个请求失败,也不会影响整体流程。
3. 结合 Array.map
动态生成 Promise 数组
这是最常见的使用方式,适用于动态生成多个异步任务:
ini
const urls = ['url1', 'url2', 'url3'];
const requests = urls.map(url => fetch(url));
Promise.all(requests)
.then(responses => Promise.all(responses.map(r => r.json())))
.then(data => console.log(data));
4. 使用 try/catch
更清晰地处理错误
配合 async/await
和 try/catch
,可以让代码结构更清晰:
javascript
async function getAllData() {
try {
const [data1, data2] = await Promise.all([
fetch('/api/data1').then(res => res.json()),
fetch('/api/data2').then(res => res.json())
]);
return { data1, data2 };
} catch (error) {
console.error('获取数据失败:', error);
}
}
5. 控制并发数量(进阶技巧)
虽然 Promise.all
默认是全部并发,但在某些场景下我们需要限制并发数量。可以借助第三方库如 p-queue
,或自己实现:
ini
async function limitConcurrency(promises, limit) {
const results = [];
for (let i = 0; i < promises.length; i += limit) {
const batch = promises.slice(i, i + limit);
const batchResults = await Promise.all(batch);
results.push(...batchResults);
}
return results;
}
6. 处理异步与同步混合的任务
Promise.all
不仅可以处理异步 Promise,还可以混合同步值:
ini
const syncValue = 42;
const asyncValue = Promise.resolve('hello');
Promise.all([syncValue, asyncValue]).then(values => {
// values = [42, 'hello']
});
7. 判断一组任务是否全部完成
通过 .finally()
可以统一处理后续逻辑:
javascript
Promise.all([task1(), task2()])
.then(() => {
console.log('所有任务都完成了');
})
.catch(() => {
console.log('有任务失败了');
})
.finally(() => {
console.log('清理资源...');
});
8. 与 Promise.race
配合使用,设置超时机制
有时候你需要给异步操作设置超时时间,可以用 Promise.race
:
javascript
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject('请求超时'), ms);
});
}
Promise.all([fetchData(), timeout(3000)])
.catch(err => console.error(err)); // 如果 3 秒内没完成就报错
9. 处理嵌套的 Promise.all
有时你会遇到多层嵌套的 Promise 结构,可以通过递归或扁平化来处理:
javascript
const nestedPromises = [
Promise.resolve(1),
[Promise.resolve(2), Promise.resolve(3)],
Promise.resolve(4)
];
// 扁平化处理
const flatPromises = nestedPromises.flat();
Promise.all(flatPromises).then(console.log); // [1, 2, 3, 4]
10. 使用 Promise.allSettled
替代方案(ES2020+)
如果你不希望因为某一个失败而中断整个流程,可以使用 Promise.allSettled
:
javascript
Promise.allSettled([Promise.resolve(1), Promise.reject('出错了'), Promise.resolve(3)])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`任务 ${index} 成功:`, result.value);
} else {
console.log(`任务 ${index} 失败:`, result.reason);
}
});
});
🧠 总结
技巧 | 用途 |
---|---|
并发请求 | 提高效率 |
错误捕获 | 防止中断 |
map 生成 Promise | 动态处理 |
async/await + try/catch | 更好的可读性 |
控制并发 | 避免资源耗尽 |
混合同步异步 | 灵活组合 |
finally 统一处理 | 清理逻辑 |
超时机制 | 增强健壮性 |
嵌套处理 | 数据结构灵活 |
allSettled 替代 | 全部完成后判断状态 |
📌 小贴士 :在使用 Promise.all
时,务必注意其"短路"特性 ------ 一旦有一个 Promise 被 reject,整个流程就会中断。根据业务需求选择是否需要使用 .catch()
或 allSettled
来替代。 如果你觉得这篇文章对你有帮助,欢迎点赞、收藏和转发,让更多开发者受益!🌟
#JavaScript #Promise #异步编程 #前端开发 #Promise.all #稀土掘金