不能直接用 form.submit() 实现队列提交,因其同步阻塞、无法控制排队/限速/进度/重试,且大文件易致内存溢出崩溃;必须用 formdata + fetch 手动实现并发可控、分片上传、状态持久化的真正队列。

为什么不能直接用 form.submit() 实现队列提交
因为 form.submit() 是同步阻塞行为,一旦触发,浏览器会立即加载所有选中的文件到内存、拼装 multipart 数据、发出请求——你完全无法插入排队、限速、进度监听或失败重试逻辑。哪怕只选了 5 个 300MB 的视频,内存占用就可能突破 1.5GB,Chrome 直接崩溃。这不是你代码写得不对,是表单机制本身不支持“队列”这个概念。
必须用 FormData + fetch 手动构造队列
真正的队列控制只能在 JavaScript 层做:遍历 input.files,为每个 File 单独创建 FormData,再用异步逻辑控制发起顺序和并发数。
- 每个文件单独
formData.append('file', file, file.name),避免混传导致进度不可分 - 用
async/await循环 + 计数器限制并发(例如最多 3 个同时 fetch),别用Promise.all(files.map(...)),否则瞬间打满连接池 - 每次 fetch 前加唯一标识字段,比如
formData.append('uploadId', crypto.randomUUID()),方便后端区分请求来源 - 服务端必须能按单文件粒度返回成功/失败,前端才能决定下一个发哪个
file.slice() 不是队列的替代品,而是大文件分片的前提
如果你要上传的是单个超大文件(比如 4GB 视频),FormData 仍会尝试一次性读入整个 Blob —— 这照样崩。此时必须先用 file.slice(start, end) 切片,再把每片作为独立 FormData 提交。注意:
- 分片大小建议
5 * 1024 * 1024(5MB),太小 HTTP 头占比高,太大 FileReader 容易内存峰值溢出 -
start和end是字节偏移量,不是文件序号;最后一片要用Math.min(start + chunkSize, file.size)算准结尾 - 每片请求必须带
Content-Range头(如bytes 0-5242879/10485759),否则服务端无法定位写入位置 - 切片上传 ≠ 队列上传:你可以对一个文件切 200 片,再用队列控制这 200 次请求的并发节奏
真正容易被忽略的点:状态持久化与中断恢复
用户刷新页面、关掉标签页、网络临时中断——这些都会让队列“断在半路”。光靠前端队列逻辑不够,你必须把已提交的文件 ID 或已上传的分片索引存到 localStorage 或 IndexedDB,并在页面重载时读取、跳过已完成项。否则所谓“队列”只是看起来有序,实际一刷新就全重来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











