秒是不用传,快传是接着传
- 文件切片
- 并发控制
- 状态记录
文件切片
File.slice() 将大文件切分为若干小文件
上传与记录
并发上传这些切片,同时在前端缓存记录下哪些已上传成功
通知合并
所有切片上传完成后,前端发送一个请求通知后端,让后端把这些切片按顺序拼回一个完整的文件
// 1、生成文件hash
const fileHash = await calculateFileHash(file);
// 2、分片大小
const CHUNK_SIZE = 2 * 1024 *1024;
const chunks = [];
let start = 0;
// 3、分片操作
while (start < file.size) {
const end = Math.min(start + CHUNK_SIZE, file.size);
chunks.push({
file: file.slice(start, end),
index: chunks.length,
start,
end,
hash: fileHash // 用于服务端校验
});
start = end;
}
// 4、从本地存储获取已上传的分片记录
const uploadChunks = JSON.parse(localStorage.getItem(fileHash) || '[]');
// 5. 找出待上传的分片
const pendingChunks = chunks.filter(chunk => !uploadedChunks.includes(chunk.index));
// 6. 控制并发数(比如3个并发)
const CONCURRENCY = 3;
async function uploadWithConcurrency() {
for (let i = 0; i < pendingChunks.length; i += CONCURRENCY) {
const batch = pendingChunks.slice(i, i + CONCURRENCY);
// 并发上传这一批
await Promise.all(batch.map((chunk) => uploadChunk(chunk));
}
}
// 7. 单个分片上传函数
async function uploadChunk(chunk) {
const formData = new FormData();
formData.append('file', chunk.file);
formData.append('index', chunk.index);
formData.append('hash', chunk.hash);
formData.append('total', chunks.length); // 总分片数
try {
const res = await Request({
url: 'https://your-api.com/upload/chunk',
method: 'POST',
data: formData,
header: { 'Content-Type': 'multipart/form-data' }
});
if (res.data.success) {
// 上传成功,记录到本地存储
uploadedChunks.push(chunk.index);
localStorage.setItem(fileHash, JSON.stringify(uploadedChunks));
// 计算并更新进度
const progress = (uploadedChunks.length / chunks.length) * 100;
console.log(`上传进度: ${progress.toFixed(2)}%`);
}
} catch (error) {
console.error(`分片 ${chunk.index} 上传失败:`, error);
// 这里可以加入重试逻辑,例如重试3次
}
}
// 8. 开始上传
uploadWithConcurrency().then(() => {
// 所有分片上传完成,通知服务端合并
Request({
url: 'https://your-api.com/upload/merge',
method: 'POST',
data: {
hash: fileHash,
fileName: file.name,
totalChunks: chunks.length
}
}).then(res => {
console.log('文件上传成功!URL:', res.data.fileUrl);
// 上传成功,清除本地记录
localStorage.removeItem(fileHash);
});
});
服务端要做的事
前端的工作如上,后端需要配合提供三个接口,这也是面试中常被问到的设计点 :
/upload/chunk:接收单个分片。通常会以文件hash_分片索引的格式临时存储。/upload/check(可选):查询已上传的分片。前端启动时调用,快速实现“断点续传”和“秒传”。/upload/merge:所有分片完成后,后端将临时分片合并,生成最终文件。
💡 高级优化与面试加分项
当你把这套逻辑讲清楚后,能主动提出以下优化点,会让面试官眼前一亮: