前端上传切片优化以及实现
你说的 前端上传切片优化以及实现,主要涉及到大文件分片上传(chunk upload)、并发控制、断点续传、秒传、重试机制等。下面我给你梳理一下实现思路和优化点。
🔹 场景与痛点
大文件上传(>100MB):直接上传会超时或失败。
网络不稳定:中断后需重传。
上传速度慢:需要并发分片上传。
服务端压力大:需要合理控制并发与分片大小。
🔹 基础实现流程
文件切片
使用Blob.slice
方法将文件分割为固定大小的分片(比如 2MB/5MB)。function createFileChunks(file: File, chunkSize = 2 * 1024 * 1024) {const chunks: Blob[] = [];let cur = 0;while (cur < file.size) {chunks.push(file.slice(cur, cur + chunkSize));cur += chunkSize;}return chunks; }
计算文件唯一标识(hash)
通常用 MD5/SHA1 或者基于文件名 + 大小 + 上次修改时间。
可以在浏览器端用spark-md5
:import SparkMD5 from "spark-md5";async function calculateHash(chunks: Blob[]) {const spark = new SparkMD5.ArrayBuffer();for (const chunk of chunks) {const buffer = await chunk.arrayBuffer();spark.append(buffer);}return spark.end(); // 文件hash }
上传分片
每个分片通过FormData
上传:async function uploadChunk(chunk: Blob, index: number, fileHash: string) {const formData = new FormData();formData.append("chunk", chunk);formData.append("index", String(index));formData.append("fileHash", fileHash);return fetch("/upload", {method: "POST",body: formData,}); }
合并文件
前端所有分片上传完成后,调用后端/merge
接口,通知服务端进行文件合并。
🔹 优化点
并发控制
使用Promise.all
并发上传,但需要限制最大并发数:async function limitUpload(chunks, limit = 5) {const pool: Promise<any>[] = [];let i = 0;async function run() {if (i >= chunks.length) return;const task = uploadChunk(chunks[i], i, "fileHash").then(run);pool.push(task);i++;}const workers = Array(limit).fill(null).map(run);await Promise.all(workers); }
断点续传
上传前向服务端查询已上传的分片列表。
跳过已完成的分片,仅上传剩余分片。
秒传
上传前计算
hash
。询问服务端该文件是否已存在,存在则直接返回成功。
失败重试
针对失败的分片,做 最多 N 次重试。
async function retry(fn, retries = 3) {while (retries--) {try {return await fn();} catch (e) {if (!retries) throw e;}} }
上传进度显示
每个分片上传时用
XMLHttpRequest.onprogress
或fetch + ReadableStream
计算进度。进度 = 已上传分片大小 / 总文件大小。
🔹 前端完整流程
选择文件 → 切片 → 计算
hash
。调用
/checkFile
→ 返回已上传分片。跳过已完成分片,继续上传剩余分片(带并发控制 & 重试机制)。
上传完后请求
/merge
。前端实时展示进度条。
🔹 技术选型
切片与上传:原生
Blob.slice
+fetch
/axios
。hash计算:
spark-md5
(大文件可用 Web Worker 避免卡 UI)。断点续传:前端记录进度 / 服务端存储分片状态。
进度显示:
XMLHttpRequest.onprogress
或axios.onUploadProgress
。