最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何利用 Promise.all() 的原子性配合 fetch 实现多文件同时上传的全成或全败逻辑
时间:2026-07-20 11:00:59 编辑:袖梨 来源:一聚教程网
Promise.all() 无原子性但可实现“全成或全败”语义,需手动检查 fetch.response.ok 并抛错;配合 AbortController 支持超时与取消;服务端须幂等+事务兜底。
Promise.all() 本身没有原子性,但能实现“全成或全败”的语义效果——只要任一 fetch 失败(包括网络错误、4xx/5xx 响应、超时等),整个上传就中止并拒绝,不执行后续逻辑。关键在于正确处理 fetch 的响应状态和错误边界,不能只依赖 Promise.all() 的默认行为。
fetch 默认不拒绝 HTTP 错误状态
fetch 在网络失败(如断网、DNS 失败)时会 reject,但对 400、500 等 HTTP 错误响应仍 resolve。若不手动检查 response.ok,Promise.all() 会把失败响应当作“成功”纳入结果数组,破坏“全败”逻辑。
✅ 正确做法:每个 fetch 后链式调用 .then() 检查 status,并主动 throw 错误:
const uploadFile = (file, url) => { const formData = new FormData(); formData.append('file', file); return fetch(url, { method: 'POST', body: formData, }) .then(response => { if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); // 或其他期望的解析 });};
统一处理上传失败与部分成功场景
使用 Promise.all() 包裹所有 uploadFile 调用,一旦任意一个抛出错误(包括网络异常、HTTP 错误、JSON 解析失败),整个 Promise.all() 立即 reject,其余仍在进行中的请求不会被取消(浏览器层面无法强制 abort 已发出的 fetch),但业务逻辑可立即停止后续操作(如 UI 提示、清理状态)。
⚠️ 注意:Promise.all() 不取消请求,仅控制逻辑流。如需真正中断上传,需配合 AbortController(见下一点)。
✅ 示例调用:
const files = [file1, file2, file3];const uploadPromises = files.map(f => uploadFile(f, '/api/upload'));Promise.all(uploadPromises) .then(results => { console.log('全部上传成功', results); // ✅ 执行“全成”后置逻辑:跳转、刷新列表、提示成功 }) .catch(err => { console.error('任一上传失败,整体视为失败', err); // ❌ 执行“全败”回滚逻辑:提示用户、保留原始文件状态、不提交表单 });
增强健壮性:添加超时与请求取消(AbortController)
原生 fetch 不支持超时,长时间卡住的请求会让 Promise.all() 无限等待。可用 AbortController 实现超时控制,并在用户主动取消时中止所有请求。
✅ 改进 uploadFile 支持 signal 和 timeout:
const uploadFile = (file, url, { timeout = 30000 } = {}) => { const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); const formData = new FormData(); formData.append('file', file); return fetch(url, { method: 'POST', body: formData, signal: controller.signal, }) .then(response => { clearTimeout(id); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return response.json(); }) .catch(err => { clearTimeout(id); if (err.name === 'AbortError') throw new Error('上传超时或已取消'); throw err; });};
服务端也要配合:幂等 + 事务兜底
前端“全成或全败”只是客户端语义。服务端必须保证:单个文件上传接口幂等(相同文件 ID 多次提交不重复存)、且批量上传应走原子事务(如数据库写入+OSS 上传绑定在同一事务中)。否则前端重试或并发可能引发数据不一致。
✅ 建议服务端设计:
- 上传前先申请 batch_id,所有文件携带该 ID;
- 后端收到全部文件后,再统一落库 + 写对象存储;
- 任一环节失败,回滚整个 batch,返回 500 或自定义错误码;
- 前端捕获该错误,触发全局失败流程。
相关文章
- rhino犀牛如何导入和调整背景图 07-31
- 大周列国志创建与更换年号条件 07-31
- ps如何设计商品促销文字字体 07-31
- ps如何设计3D蓝光立体文字 07-31
- ps如何设计挤压文字 07-31
- ps如何设计银光环绕的文字效果 07-31