前端上传切片优化以及实现

你说的 前端上传切片优化以及实现,主要涉及到大文件分片上传(chunk upload)、并发控制、断点续传、秒传、重试机制等。下面我给你梳理一下实现思路和优化点。


🔹 场景与痛点

  • 大文件上传(>100MB):直接上传会超时或失败。
  • 网络不稳定:中断后需重传。
  • 上传速度慢:需要并发分片上传。
  • 服务端压力大:需要合理控制并发与分片大小。

🔹 基础实现流程

  1. 文件切片

    使用 Blob.slice 方法将文件分割为固定大小的分片(比如 2MB/5MB)。

    ini 复制代码
    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;
    }
  2. 计算文件唯一标识(hash)

    通常用 MD5/SHA1 或者基于文件名 + 大小 + 上次修改时间。

    可以在浏览器端用 spark-md5

    javascript 复制代码
    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
    }
  3. 上传分片

    每个分片通过 FormData 上传:

    php 复制代码
    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,
      });
    }
  4. 合并文件

    前端所有分片上传完成后,调用后端 /merge 接口,通知服务端进行文件合并。


🔹 优化点

  1. 并发控制

    使用 Promise.all 并发上传,但需要限制最大并发数:

    ini 复制代码
    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);
    }
  2. 断点续传

    • 上传前向服务端查询已上传的分片列表。
    • 跳过已完成的分片,仅上传剩余分片。
  3. 秒传

    • 上传前计算 hash
    • 询问服务端该文件是否已存在,存在则直接返回成功。
  4. 失败重试

    • 针对失败的分片,做 最多 N 次重试
    javascript 复制代码
    async function retry(fn, retries = 3) {
      while (retries--) {
        try {
          return await fn();
        } catch (e) {
          if (!retries) throw e;
        }
      }
    }
  5. 上传进度显示

    • 每个分片上传时用 XMLHttpRequest.onprogressfetch + ReadableStream 计算进度。
    • 进度 = 已上传分片大小 / 总文件大小。

🔹 前端完整流程

  1. 选择文件 → 切片 → 计算 hash
  2. 调用 /checkFile → 返回已上传分片。
  3. 跳过已完成分片,继续上传剩余分片(带并发控制 & 重试机制)。
  4. 上传完后请求 /merge
  5. 前端实时展示进度条。

🔹 技术选型

  • 切片与上传 :原生 Blob.slice + fetch/axios
  • hash计算spark-md5(大文件可用 Web Worker 避免卡 UI)。
  • 断点续传:前端记录进度 / 服务端存储分片状态。
  • 进度显示XMLHttpRequest.onprogressaxios.onUploadProgress

相关推荐
豐儀麟阁贵9 小时前
8.5在方法中抛出异常
java·开发语言·前端·算法
zengyuhan50310 小时前
Windows BLE 开发指南(Rust windows-rs)
前端·rust
醉方休10 小时前
Webpack loader 的执行机制
前端·webpack·rust
前端老宋Running10 小时前
一次从“卡顿地狱”到“丝般顺滑”的 React 搜索优化实战
前端·react.js·掘金日报
隔壁的大叔10 小时前
如何自己构建一个Markdown增量渲染器
前端·javascript
用户44455436542610 小时前
Android的自定义View
前端
WILLF10 小时前
HTML iframe 标签
前端·javascript
枫,为落叶10 小时前
Axios使用教程(一)
前端
小章鱼学前端10 小时前
2025 年最新 Fabric.js 实战:一个完整可上线的图片选区标注组件(含全部源码).
前端·vue.js
ohyeah10 小时前
JavaScript 词法作用域、作用域链与闭包:从代码看机制
前端·javascript