主题
并发请求
并发请求指的是:多个异步请求互不依赖时,同时发起,再按需要统一等待结果,而不是一个请求结束后再发下一个。
什么场景会用到
常见情况包括:
- 页面初始化时同时请求多个独立接口
- 批量读取多个资源
- 多个任务可以并行执行,不存在前后依赖
串行和并发的区别
下面是串行:
js
const user = await getUser()
const settings = await getSettings()
const permissions = await getPermissions()这种写法会一个接一个地等待。
下面是并发:
js
const userPromise = getUser()
const settingsPromise = getSettings()
const permissionsPromise = getPermissions()
const [user, settings, permissions] = await Promise.all([userPromise, settingsPromise, permissionsPromise])这里三个请求会尽早一起发出。
最常见的方式:Promise.all
js
const [user, settings] = await Promise.all([getUser(), getSettings()])Promise.all 的规则可以直接记成:
- 全部成功才成功
- 只要一个失败就整体失败
- 返回结果顺序和传入顺序一致,不看完成先后
一个基础例子
js
async function loadPageData() {
const [user, posts, notices] = await Promise.all([fetchUser(), fetchPosts(), fetchNotices()])
return { user, posts, notices }
}这适合“页面展示依赖全部数据都到齐”的场景。
不是所有场景都该用 Promise.all
如果希望“每个请求都执行完,再统一看结果”,更适合 Promise.allSettled:
js
const results = await Promise.allSettled([taskA(), taskB(), taskC()])这适合:
- 批量任务统计
- 局部失败可接受
- 不希望一个失败打断全部流程
并发不等于无限制同时发送
这是一个高频误区。
“并发”只表示多个任务重叠进行,不等于可以无上限同时发起。
如果一次性发出太多请求,可能带来:
- 服务端压力增大
- 浏览器连接数受限
- 页面瞬时资源占用过高
- 失败重试雪上加霜
需要限流时怎么做
如果任务很多,通常要做“限并发”而不是“全并发”。
可以把它理解成:同一时间只允许固定数量的请求同时进行。
js
async function runWithLimit(tasks, limit) {
const results = []
const executing = new Set()
for (const task of tasks) {
const promise = Promise.resolve().then(task)
results.push(promise)
executing.add(promise)
promise.finally(() => {
executing.delete(promise)
})
if (executing.size >= limit) {
await Promise.race(executing)
}
}
return Promise.all(results)
}这类模式适合批量上传、批量抓取、批量同步任务。
错误处理要先想清楚
并发请求最容易忽略的是“失败策略”:
- 是一个失败就整体中断
- 还是保留成功结果,单独记录失败项
- 是否需要重试
- 是否需要超时控制
例如:
js
try {
const [user, settings] = await Promise.all([getUser(), getSettings()])
} catch (error) {
console.error('load failed', error)
}如果希望部分成功也保留结果,就不该直接只用 Promise.all。
await 连写不一定是并发
这也是最常见的误区之一。
js
const a = await fetchA()
const b = await fetchB()这通常是串行,不是并发。
真正的并发写法通常是先拿到 Promise,再统一等待:
js
const aPromise = fetchA()
const bPromise = fetchB()
const [a, b] = await Promise.all([aPromise, bPromise])使用建议
- 任务互不依赖时,优先考虑并发。
- 全部成功才继续时,用
Promise.all。 - 需要保留每项结果时,用
Promise.allSettled。 - 任务数量很大时,不要直接全并发,优先考虑限并发。
