大文件切片上传

秒是不用传,快传是接着传

  • 文件切片
  • 并发控制
  • 状态记录
文件切片

File.slice() 将大文件切分为若干小文件

上传与记录

并发上传这些切片,同时在前端缓存记录下哪些已上传成功

通知合并

所有切片上传完成后,前端发送一个请求通知后端,让后端把这些切片按顺序拼回一个完整的文件

文件切片与状态管理.js 复制代码
// 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) || '[]');
并发控制与断点续传.js 复制代码
// 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);
  });
});

服务端要做的事

前端的工作如上,后端需要配合提供三个接口,这也是面试中常被问到的设计点

  1. /upload/chunk :接收单个分片。通常会以文件hash_分片索引的格式临时存储。
  2. /upload/check(可选):查询已上传的分片。前端启动时调用,快速实现"断点续传"和"秒传"。
  3. /upload/merge:所有分片完成后,后端将临时分片合并,生成最终文件。

💡 高级优化与面试加分项

当你把这套逻辑讲清楚后,能主动提出以下优化点,会让面试官眼前一亮:

  • 秒传 :在初始化上传前,先根据文件hash请求后端。如果文件已存在,直接返回成功,一秒完成
  • Web Worker :将计算文件hash这种CPU密集型任务放到Web Worker里执行,避免阻塞页面渲染
  • 本地存储选型 :小文件、少量记录用localStorage;大文件、复杂记录用IndexedDB
  • 暂停/恢复 :通过AbortController来取消进行中的请求,实现暂停功能。恢复时,只需重新调用上传逻辑,pendingChunks会自动过滤掉已上传的部分
相关推荐
JustHappy9 小时前
古法编程秘籍(二):什么是代码模块化?别背概念,把房间收拾明白就够了
前端·后端
小江的记录本9 小时前
【JVM虚拟机】堆内存分代模型:年轻代(Eden+Survivor)、老年代、元空间Metaspace(附《思维导图》+《面试高频考点清单》)
java·前端·jvm·后端·python·spring·面试
weixin_471383039 小时前
图片预解码缓存
前端·浏览器缓存·图片预解码
郑洁文11 小时前
基于网络爬虫的Web敏感信息泄露自动化检测工具
前端·爬虫·网络安全·自动化
郑洁文12 小时前
可视化Web渗透分析工具的设计与实现
前端
罗超驿12 小时前
18.Web API 实战:元素与表单属性的获取和修改
开发语言·前端·javascript
边界条件╝12 小时前
微前端进阶(四)
前端·状态模式
无风听海12 小时前
JSON Web Token(JWT)完全指南
java·前端·json
IT_陈寒13 小时前
Python闭包里藏的这个坑,差点让我加班到凌晨
前端·人工智能·后端
IT_陈寒13 小时前
Java注解空指针?这个坑我踩得莫名其妙
前端·人工智能·后端