题目重点:把逐个请求改成有界并行批次,保留输入顺序并正确处理HTTP与JSON错误。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 明确问客户端fetch data→JSON,parallel及batch优化,但没有API schema、服务端batch endpoint或并发上限。练习采用单URL请求,每批最多B个并行,批次串行,不虚构服务端批量协议。
- 输出每个已调度URL的fulfilled/value或rejected/error,按输入顺序;重复URL视为两次请求,不去重。注入fetch便于独立验证;不保证某结果字段结构来自实际接口。
解题路线
- 串行await一条再发下一条,等待时间接近各延迟之和;同批并行可把该批等待缩至最慢请求附近。但无界Promise.all(urls.map(...))会同时调度所有请求,占用连接、限流预算与内存。
- 按B切片,Promise.allSettled并行请求并解析JSON;每批结束再发下一批。响应HTTP错误必须检查response.ok,不能把fetch正常返回Response视为业务成功;JSON解析也可能失败。
- allSettled保证一条失败不抹掉同批成功;返回顺序按输入promise顺序,不依赖完成顺序。每条保存明确失败信息,后续重试只针对可重试项,并需要总deadline和退避预算。
- 固定批次有队头等待:其中一条慢请求会让下一批所有任务延后。更均匀吞吐可用B个worker共享任务索引,某worker完成即领下一项,结果仍写原索引;这是后续优化,不把当前代码称为持续满负荷pool。
- 这里batch是客户端调度分组。真正HTTP batch需要服务端协议支持每子项ID、错误、响应大小与重试语义,才能减少请求数;不能仅把数组拼成JSON就假设接口支持。
- 传入AbortSignal给全部fetch;批次完成后若已abort,不调度下一批。取消不保证服务器没处理请求,示例结果只覆盖已调度部分;若需要每输入一个结果,应给未调度项单独cancelled状态。
手动走一遍
URL[a,b,c,d,e],B2时先并发a/b,再c/d,再e。b返回503被记为rejected;a正常JSON仍保留。即使b先完成,结果也按a、b顺序。若c解析坏JSON,其HTTP200也不是成功。
JavaScript 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
export async function fetchJSONBatches(urls, { batchSize = 4, fetchImpl = fetch, signal } = {}) {
if (!Number.isInteger(batchSize) || batchSize < 1) throw new RangeError("positive batchSize");
const results = [];
for (let offset = 0; offset < urls.length; offset += batchSize) {
const batch = urls.slice(offset, offset + batchSize);
const outcomes = await Promise.allSettled(batch.map(async (url) => {
const response = await fetchImpl(url, { signal });
if (!response.ok) throw new Error("HTTP " + response.status);
return await response.json();
}));
for (let i = 0; i < batch.length; i++) {
const outcome = outcomes[i];
results.push(outcome.status === "fulfilled"
? { url: batch[i], status: "fulfilled", value: outcome.value }
: { url: batch[i], status: "rejected", error: String(outcome.reason?.message ?? outcome.reason) });
}
if (signal?.aborted) break;
}
return results;
}
复杂度
按N个URL、B上限,结果O(N)空间,活动请求/批临时状态O(B),实际响应体总大小需另计。均匀延迟L的理想等待约ceil(N/B)×L,不能保证网络/限流下严格N/B倍加速。客户端分批仍发N个HTTP请求。
易错点与追问
容易失分的边界
- fetch遇404/503通常不会自动reject,遗漏ok检查。
- 把并行完成顺序当输入顺序。
- 将客户端批次当服务端batch协议,虚报减少请求数量。
继续深挖
- 如何实现持续worker池并证明活跃请求≤B?
- 哪些GET失败可重试?若换成POST,重试需要什么幂等键?
- 海量JSON是否应边处理边释放,而不是累积全部结果?
技术参考
- Fetch响应与错误处理:技术语义参考,具体题目按本文约定。
