异步文件分片上传结合 promise.allsettled 实现失败分片单项重试:先并发上传并聚合结果,再对 rejected 分片按指数退避策略重试,全部成功后才发起合并请求。

异步文件分片上传结合 Promise.all 实现失败分片单项重试,核心在于:不直接用 Promise.all 阻塞式等待全部完成,而是先并发上传所有分片、收集结果,再对失败项单独重试,避免单点失败导致整体失败。
分片上传前的准备:切片与元信息管理
将大文件按固定大小(如 2MB)切分为 Blob 数组,并为每个分片生成唯一标识(如 fileId + index),同时携带校验信息(如 hash 或 md5)。建议封装为函数:
- 使用
File.slice()或Blob.slice()切片,注意浏览器兼容性(slice参数为(start, end, type)) - 维护一个分片任务列表:
const chunks = chunks.map((chunk, i) => ({ blob: chunk, index: i, fileId })) - 上传前可预检服务端是否已存在该分片(断点续传关键)
并发上传 + 结果聚合:用 Promise.allSettled 替代 Promise.all
Promise.all 一失败就 reject,不适合容错场景;应改用 Promise.allSettled,它始终 resolve 并返回每个 Promise 的状态(fulfilled 或 rejected):
const results = await Promise.allSettled( chunks.map(chunk => uploadChunk(chunk)) );
- 遍历
results,筛选出status === 'rejected'的项,提取其chunk.index和错误原因 - 保留成功项的响应数据(如服务端返回的分片标识、签名等),用于后续合并请求
- 注意:不要在
uploadChunk内吞掉错误,确保 rejection 携带必要上下文(如new Error(`upload failed for chunk ${index}: ${err.message}`))
单项重试策略:指数退避 + 有限次数
对失败分片单独发起重试,避免重复上传成功项。推荐封装重试函数:
async function retryUpload(chunk, maxRetries = 3) {
for (let i = 0; i setTimeout(r, Math.pow(2, i) * 1000)); // 1s, 2s, 4s
}
}
}
- 调用时对每个失败分片执行
retryUpload(failedChunk),仍可用Promise.allSettled并发重试(非必须,视服务端压力而定) - 重试前可加简单判断:如网络离线则跳过,或检查分片是否已被服务端确认接收(通过预检接口)
- 记录重试日志(如
console.warn(`Retrying chunk ${index}, attempt ${i + 1}`)),便于调试
合并与收尾:仅当所有分片成功后提交合并请求
重试完成后,再次检查所有分片状态。只有全部 fulfilled,才向服务端发起「合并」请求(如 POST /merge?fileId=xxx):
- 合并请求需携带所有成功分片的服务端标识(如 etag、uploadId 等),服务端据此校验并拼接
- 前端收到合并成功响应后,才算整个上传完成;若合并失败(如超时、校验不一致),需整体回滚或告警
- 可配合进度条:总进度 = (成功分片数 + 重试中分片数 × 0.5)/ 总分片数,提升用户体验
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











