一个小小的 await 顺序,可能让你的接口总耗时翻倍
在现代前端开发中,axios 搭配 async/await 几乎是请求接口的标配写法。但很多人可能没意识到:同样是写 await,两个接口的完成时间可能相差一倍。
场景复现
假设你有两个接口:接口 A 和接口 B,每个都需要较长时间才能返回数据(比如各需 10 秒)。
现在你需要在同一个 async 函数里依次请求它们,最后拿到两个数据。
来看这段代码:
async function fetchData() {
const resA = await axios.get('/api/A'); // 耗时较长
const resB = await axios.get('/api/B'); // 耗时较长
return [resA, resB];
}
问题:这个函数的总执行时间是多长?
- 等于单个接口的时间?
- 还是两个接口时间之和?
答案是 两个接口时间之和(例如 10+10=20 秒)。
因为 await 会阻塞后续代码的执行:先等 A 完成,再开始请求 B,两个请求是串行的。
真正的“同时请求”:只需要最慢那个接口的时间
很多时候,接口 A 和接口 B 之间并没有依赖关系(B 不需要 A 的返回结果)。这种情况下,完全可以让它们并行发起,从而把总耗时压缩到 单个最慢接口的耗时。
并行写法一:先发起请求,后 await
async function fetchData() {
const promiseA = axios.get('/api/A'); // 立即发起,不等待
const promiseB = axios.get('/api/B'); // 立即发起,不等待
const [resA, resB] = await Promise.all([promiseA, promiseB]);
return [resA, resB];
}
并行写法二:直接 Promise.all
async function fetchData() {
const [resA, resB] = await Promise.all([
axios.get('/api/A'),
axios.get('/api/B')
]);
return [resA, resB];
}
两种写法效果完全一样:两个请求几乎同时发出,总耗时 ≈ max(耗时A, 耗时B)。
对比一览
| 写法 | 执行方式 | 总耗时 |
|---|---|---|
顺序 await(A 完再 B) |
串行 | 耗时A + 耗时B |
Promise.all + 同时发起 |
并行 | max(耗时A, 耗时B) |
什么时候该用并行,什么时候该用串行?
-
用并行:两个接口互不依赖(比如同时获取用户信息、系统配置、商品列表)。
效果:更快,用户少等待。 -
用串行:后一个接口依赖前一个接口的返回结果(比如先登录获得 token,再用 token 请求用户详情)。
效果:逻辑正确。
一个常见的坑
新手容易写成这样:
async function fetchData() {
const resA = await axios.get('/api/A');
const resB = await axios.get('/api/B'); // 没依赖也等A结束
// ...
}
或者在循环里无意识地串行:
const ids = [1, 2, 3];
for (const id of ids) {
await axios.get(`/api/item/${id}`); // 三个请求串行,总时间累加
}
如果这些请求彼此独立,应该用 Promise.all 或 Promise.allSettled 并行处理。
小结
async/await本身不决定串行或并行——决定权在于你何时使用await。- 默认顺序
await= 串行,总耗时 = 各接口耗时之和。 - 想让多个请求同时发出、总耗时取最长者,请使用
Promise.all。
记住这个区别,下次写接口请求时就能帮用户省下成倍的等待时间 —— 积少成多,体验优化就从这一个小细节开始。