JS—大文件上传

个人博客:haichenyi.com。感谢关注

一. 目录

  • 一–目录
  • 二–分片上传
  • 三–生成文件唯一标识(文件哈希)​
  • 四–断点续传 & 秒传
  • 五–分片上传(并发控制)​
  • 六–服务端合并分片​
  • 七–优化​
  • 八–总结​

  大文件上传的核心痛点是:文件过大,用户网络环境不稳定,服务器压力过大,容易中断,用户体验极差。只要解决这几个问题就行了。其实,最重要的一个问题就是文件过大。文件太大了,我们就分成几份上传就行了。这就是分片。

大文件上传的核心流程​
​​1. ​​前端分片​​ → 2. ​​计算文件唯一标识​​ → 3. ​​上传分片​​ → 4. ​​服务端合并分片​​ → 5. ​​完整性校验​

二. 分片上传

  将大文件分割成多个固定的小文件,减少单次请求的压力。举个栗子:100M的文件,分成10份,每个10M,这样就可以解决问题。核心代码如下

//主要就是File.slice
function createFileChunks(file, chunkSize = 10 * 1024 * 1024) {
    //分片数组
    const chunks = []
    //文件总大小
    const fileSize = file.size
    let start = 0
    while (start < fileSize) {
        //单个分片
        let chunk = {
            //文件数据
            chunk: file.slice(start, start + fileSize),
            //索引,用于文件合并时的顺序
            index: chunks.length
        }
        chunks.push(chunk)
        start += chunkSize
    }
    return chunks
}

三. 生成文件唯一标识(文件哈希)

  使用文件内容生成唯一标识,用于标识文件,实现秒传和断点续传。代码如下

function calculateFileHash(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        const spark = new SparkMD5.ArrayBuffer();
        reader.readAsArrayBuffer(file);
        reader.onload = (e) => {
            spark.append(e.target.result);
            const hash = spark.end();
            resolve(hash);
        };
    })
}

四. 断点续传 & 秒传

秒传: 在上传之前,检查服务端是否存在已经有相同哈希值的文件,有则跳过,没有,则上传
断点续传: 上传前,检查已经上传的分片列表,跳过已上传的分片

五. 分片上传(并发控制)

使用Promise池控制并发数(如同时上传3个分片),避免浏览器阻塞。

async function uploadChunks(chunks, fileHash, concurrency = 3) {
  const pool = new Set(); // 并发池
  for (const { chunk, index } of chunks) {
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('hash', fileHash);
    formData.append('index', index);

    const task = fetch('/api/upload-chunk', {
      method: 'POST',
      body: formData,
    }).then(() => {
      pool.delete(task);
    });

    pool.add(task);
    if (pool.size >= concurrency) {
      await Promise.race(pool); // 等待任意任务完成
    }
  }
  await Promise.all(pool); // 等待剩余任务完成
}

六. 服务端合并分片

当文件分片全都上传完成之后,前端触发文件合并逻辑,服务端合并文件。我们上传文件分片的时候上传了文件的hash值和索引。直接按照文件的hash值过滤出同一个文件的分片,然后按照索引,一次写入file即可。

七. 优化​

  1. 分片上传进度显示​。
  2. 错误重试机制​,为每个分片上传添加重试逻辑(最多3次)。
  3. 浏览器本地持久化,使用localStorage或IndexedDB保存上传状态,页面刷新后恢复。

八. 总结

大文件上传的核心在于​​分治策略​​:

  • 分片​​:将大问题拆解为小任务
  • 断点续传​​:增强容错能力
  • 并发控制​​:平衡速度与稳定性

你可能感兴趣的:(Web知识点,javascript,开发语言,ecmascript,大文件上传)