JavaScript 并发控制
Promise 提供多种并发控制方法,用于管理多个异步任务的执行和结果处理。
Promise.all
JavaScript
// 所有 Promise 成功才返回,一个失败立即拒绝
const promises = [
fetch('/api/user'),
fetch('/api/posts'),
fetch('/api/comments')
];
Promise.all(promises)
.then(results => {
// results 是数组,顺序对应 promises
const [user, posts, comments] = results;
console.log('全部成功:', user, posts, comments);
})
.catch(error => {
// 任意一个失败,立即触发
console.error('有失败:', error);
});
// 空数组直接返回空数组
Promise.all([]).then(results => console.log(results)); // []
Promise.all 失败处理
JavaScript
// Promise.all 快速失败特性
const p1 = Promise.resolve('成功1');
const p2 = Promise.reject('失败');
const p3 = Promise.resolve('成功2');
Promise.all([p1, p2, p3])
.then(results => console.log(results))
.catch(error => console.log('第一个失败:', error)); // '失败'
// 不关心失败时使用 Promise.allSettled
// 或者包装每个 Promise 避免失败传播
const wrappedPromises = [p1, p2, p3].map(p =>
p.catch(error => ({ status: 'failed', error }))
);
Promise.all(wrappedPromises)
.then(results => console.log(results));
// [{ status: 'success', value: '成功1' }, { status: 'failed', error: '失败' }, ...]
Promise.race
JavaScript
// 返回最先完成的结果(无论成功或失败)
const promises = [
new Promise(r => setTimeout(() => r('慢'), 1000)),
new Promise(r => setTimeout(() => r('快'), 100)),
new Promise((_, r) => setTimeout(() => r('失败'), 500))
];
Promise.race(promises)
.then(result => console.log('最快成功:', result)) // '快'
.catch(error => console.log('最快失败:', error));
// 实际应用:请求超时
function fetchWithTimeout(url, timeout = 5000) {
const fetchPromise = fetch(url);
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), timeout)
);
return Promise.race([fetchPromise, timeoutPromise]);
}
// 使用
fetchWithTimeout('/api/data', 3000)
.then(response => response.json())
.catch(error => console.log(error.message)); // 可能是"请求超时"
Promise.allSettled
JavaScript
// 等待所有 Promise 完成,返回每个的状态(ES2020)
const promises = [
Promise.resolve('成功1'),
Promise.reject('失败'),
Promise.resolve('成功2')
];
Promise.allSettled(promises)
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
// 输出:
// [{ status: 'fulfilled', value: '成功1' },
// { status: 'rejected', reason: '失败' },
// { status: 'fulfilled', value: '成功2' }]
Promise.any(ES2021)
JavaScript
// 等待第一个成功的 Promise,全部失败才拒绝
const promises = [
Promise.reject('失败1'),
Promise.resolve('成功'),
Promise.reject('失败2')
];
Promise.any(promises)
.then(result => console.log('第一个成功:', result)) // '成功'
.catch(error => {
// AggregateError:所有失败的集合
console.log('全部失败:', error.errors);
});
// 全部失败示例
Promise.any([
Promise.reject('失败1'),
Promise.reject('失败2')
]).catch(error => {
console.log(error instanceof AggregateError); // true
console.log(error.errors); // ['失败1', '失败2']
});
四种方法对比
| 方法 | 成功条件 | 失败条件 | 返回值 |
|---|---|---|---|
Promise.all | 全部成功 | 任一失败 | 结果数组 |
Promise.race | 任一完成 | 任一失败(最先) | 单个结果 |
Promise.allSettled | 无(永不失败) | 无 | 状态数组 |
Promise.any | 任一成功 | 全部失败 | 单个结果 |
JavaScript
// 选择指南:
// 1. 需要全部成功 → Promise.all
// 2. 需要最快结果 → Promise.race
// 3. 需要全部状态 → Promise.allSettled
// 4. 需要任一成功 → Promise.any
并发限制
JavaScript
// Promise.all 不限制并发数量,可能资源耗尽
// 实现并发限制
async function promiseLimit(tasks, limit = 3) {
const results = [];
const executing = new Set();
for (const task of tasks) {
const promise = Promise.resolve(task()).then(result => {
executing.delete(promise);
return result;
});
executing.add(promise);
results.push(promise);
if (executing.size >= limit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
// 使用:限制并发数为 3
const tasks = urls.map(url => () => fetch(url));
const results = await promiseLimit(tasks, 3);
// 更简洁的实现
class PromisePool {
constructor(limit) {
this.limit = limit;
this.queue = [];
this.active = 0;
}
async run(task) {
while (this.active >= this.limit) {
await new Promise(resolve => this.queue.push(resolve));
}
this.active++;
try {
return await task();
} finally {
this.active--;
if (this.queue.length) {
this.queue.shift()();
}
}
}
}
// 使用
const pool = new PromisePool(5);
const results = await Promise.all(urls.map(url => pool.run(() => fetch(url))));
实际应用场景
JavaScript
// 并行请求多个接口
async function fetchAllData(userId) {
const [user, posts, comments] = await Promise.all([
fetch(`/api/user/${userId}`).then(r => r.json()),
fetch(`/api/posts/${userId}`).then(r => r.json()),
fetch(`/api/comments/${userId}`).then(r => r.json())
]);
return { user, posts, comments };
}
// 批量上传,记录成功和失败
async function batchUpload(files) {
const results = await Promise.allSettled(
files.map(file => uploadFile(file))
);
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 };
}
// 多源备份,取最快成功的
async function fetchFromBackup(primary, backups) {
return Promise.any([
fetch(primary),
...backups.map(url => fetch(url))
]);
}
// 验证多个条件,全部满足
async function validateAll(conditions) {
await Promise.all(conditions.map(check => check()));
return true; // 全部通过
}
注意事项
Promise.all一个失败立即拒绝,不等待其他完成Promise.race返回最先完成的,可能是失败Promise.allSettled永不拒绝,适合记录全部状态Promise.any全部失败才拒绝,返回 AggregateError
JavaScript
// Promise.all 不等待失败后的 Promise
const slow = new Promise(r => setTimeout(() => r('慢'), 1000));
const fastFail = Promise.reject('快失败');
Promise.all([slow, fastFail])
.catch(error => {
console.log('失败:', error); // 立即输出,不等 slow
// slow 仍在执行,但结果被忽略
});
// 如需等待全部完成,用 Promise.allSettled
Promise.allSettled([slow, fastFail])
.then(results => {
// 等待 slow 完成(1秒后)
console.log(results);
});
要点总结
Promise.all:全部成功才返回,一个失败立即拒绝Promise.race:返回最先完成的结果(成功或失败)Promise.allSettled:等待全部完成,返回状态数组(永不失败)Promise.any:返回第一个成功,全部失败才拒绝(AggregateError)- 并发限制需手动实现(队列 + Promise.race)
- 选择方法依据业务需求:全部成功、最快结果、全部状态、任一成功
Promise.all不等待失败后的其他 Promise
📝 发现内容有误?点击此处直接编辑