推荐使用async和await 代替Promise
替代回调函数和 Promise 链式调用,以提高代码的可读性。而且使用 async/await 也可以很方便地控制异步请求的执行顺序。
1、顺序执行(一个接一个)
最基本的用法就是按顺序 await 每个异步操作:
async function sequentialRequests() {
// 第一个请求先执行
const result1 = await fetch('/api/first');
const data1 = await result1.json();
// 第一个完成后,再执行第二个
const result2 = await fetch('/api/second');
const data2 = await result2.json();
return { data1, data2 };
}
2、并行执行后顺序处理
如果需要先发起所有请求,然后按特定顺序处理结果:
async function parallelThenSequential() {
// 同时发起所有请求
const promise1 = fetch('/api/first').then(res => res.json());
const promise2 = fetch('/api/second').then(res => res.json());
// 按顺序等待结果
const data1 = await promise1;
const data2 = await promise2;
return { data1, data2 };
}
3、动态顺序执行(根据前一个请求结果决定)
async function conditionalRequests() {
const user = await fetch('/api/user').then(res => res.json());
// 根据第一个请求的结果决定是否执行第二个
if (user.needsDetails) {
const details = await fetch(`/api/details/${user.id}`).then(res => res.json());
return { user, details };
}
return { user };
}
4、循环中的顺序执行
async function sequentialInLoop(urls) {
const results = [];
for (const url of urls) {
const response = await fetch(url);
results.push(await response.json());
}
return results;
}
5、 使用 try-catch 处理顺序请求中的错误
使用一个catch捕获替代.then().catch()
async function sequentialWithErrorHandling() {
try {
const result1 = await fetch('/api/first');
const data1 = await result1.json();
const result2 = await fetch('/api/second');
const data2 = await result2.json();
return { data1, data2 };
} catch (error) {
console.error('请求失败:', error);
throw error; // 或者返回默认值
}
}
结合使用Promise处理并行执行情况
虽然推荐使用 async/await,但要明白它们与 Promise 是互补关系而非替代关系
1、 并行执行后不按照顺序处理(结合 Promise 的方法)
async function recommendedApproach() {
try {
const [data1, data2] = await Promise.all([
//返回r.json()
fetch('/api/first').then(r => r.json()),
//返回r.json()
fetch('/api/second').then(r => r.json())
]);
return { data1, data2 };
} catch (error) {
// 统一错误处理
console.error('请求失败:', error);
throw error;
}
}
2、允许并行时,部分接口失败的情况
async function fetchMultipleAPIs() {
const [users, posts, products] = await Promise.allSettled([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/products').then(r => r.json())
]);
// 处理失败请求
[users, posts, products].forEach(result => {
if (result.status === 'rejected') {
console.error('请求失败:', result.reason.message);
}
});
// 返回成功的数据(失败的设为null)
return {
users: users.status === 'fulfilled' ? users.value : null,
posts: posts.status === 'fulfilled' ? posts.value : null,
products: products.status === 'fulfilled' ? products.value : null
};
}
// 使用示例
fetchMultipleAPIs()
.then(data => {
console.log('获取到的数据:', data);
// 示例输出:
// 如果 posts 请求失败:
// {
// users: [...],
// posts: null,
// products: [...]
// }
});
3、并行请求的性能优化建议
对于大量并行请求,建议增加并发控制:
async function parallelWithLimit(urls, limit = 5) {
const results = [];
for (let i = 0; i < urls.length; i += limit) {
const chunk = urls.slice(i, i + limit);
const chunkResults = await Promise.allSettled(
chunk.map(url => fetch(url).then(r => r.json()))
);
results.push(...chunkResults);
}
return results;
}
4、取消请求的支持
结合 AbortController 实现可取消的请求, 这个可以不考虑一般已经封装在了项目的request中
async function cancellableFetch(url, { signal } = {}) {
const response = await fetch(url, { signal });
if (signal?.aborted) throw new Error('请求被取消');
return response.json();
}
// 使用示例
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000); // 5秒后取消
try {
const data = await cancellableFetch('/api/data', {
signal: controller.signal
});
} catch (err) {
if (err.message === '请求被取消') {
console.log('主动取消请求');
}
}
关键点总结
- await 会暂停函数执行,直到 Promise 解决,所以顺序排列的 await 会按顺序执行
- 如果不关心前一个请求的结果,只是要确保顺序,可以直接顺序 await
- 如果需要提高性能,可以先并行发起请求,然后顺序处理结果
- 错误处理很重要,可以使用 try-catch 包裹多个顺序请求
记住,async/await 只是 Promise 的语法糖,本质上还是在操作 Promise。选择顺序执行还是并行执行取决于业务需求和对性能的要求。