async/await实现视频分片上传的核心是分片切割、有序/并发上传、服务端合并;需用blob.slice()分片避免内存溢出,控制顺序与重试,保持ui响应。

用 async/await 实现视频分片上传,核心是把大文件切分成小块、按序(或并发)上传、最后通知服务端合并。关键在于控制分片顺序、处理失败重试、避免内存溢出,并保持 UI 可响应。
1. 分片切割:用 Blob.slice() 拆分视频文件
不要一次性读取整个视频到内存(尤其手机端易崩溃),而是用 Blob.slice() 按字节范围提取分片:
function createChunks(file, chunkSize = 2 * 1024 * 1024) { // 2MB/片
const chunks = [];
for (let start = 0; start 注意:Blob.slice() 是浅拷贝,不复制实际数据,性能好、内存友好。
2. 单片上传:封装带重试的 async 函数
每片上传独立,失败可重试,用 async/await 让逻辑线性清晰:
async function uploadChunk(chunk, index, uploadId, retry = 3) {
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('index', index);
formData.append('uploadId', uploadId);
<p>for (let i = 0; i HTTP ${res.status});
return await res.json(); // 如返回 { success: true }
} catch (err) {
if (i === retry) throw err;
await new Promise(r => setTimeout(r, 1000 * (i + 1))); // 指数退避
}
}
}</p>3. 控制上传流程:串行 or 并发?推荐有限并发
全串行太慢,全并发可能压垮浏览器或服务端。建议用 Promise.allSettled + 并发数限制:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 定义最大并发数(如 3~5),避免卡顿和请求被拒
- 用队列方式分批执行,每批上传完再启下一批
- 实时更新进度(如
uploadedCount / totalChunks)
async function uploadAllChunks(chunks, uploadId) {
const concurrency = 3;
const results = [];
<p>for (let i = 0; i
uploadChunk(chunk, i + idx, uploadId)
);
const batchResults = await Promise.allSettled(batchPromises);
results.push(...batchResults);</p><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">// 可选:更新 UI 进度
const uploaded = i + batch.length;
console.log(`已上传 ${uploaded}/${chunks.length} 片`);}
const failed = results.filter(r => r.status === 'rejected');
if (failed.length > 0) throw new Error(共 ${failed.length} 片上传失败
return { uploadId, total: chunks.length }; }
4. 合并与校验:上传完成后调用 merge 接口
所有分片成功后,主动通知服务端合并并校验完整性(如传 MD5 或 SHA-1):
async function mergeVideo(uploadId, fileName, fileSize) {
const res = await fetch('/api/upload/merge', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
uploadId,
fileName,
fileSize,
// 可选:前端预计算的文件 hash(需 FileReader + SparkMD5 等)
}),
});
if (!res.ok) throw new Error('合并失败');
return res.json(); // 返回最终视频 URL 或信息
}注意:服务端必须校验分片数量、顺序、大小总和,防止缺片或乱序。
不复杂但容易忽略:上传前建议先查服务端是否已存在同名文件(秒传)、支持断点续传(服务端记录已收分片)、前端加取消信号(AbortController)。这些都能基于 async/await 自然扩展。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










