You need to enable JavaScript to run this app. XMLHttpRequest(JS/React)分片上传大文件时浏览器崩溃的解决办法问询
优惠活动
大模型
产品
解决方案
定价
更多

XMLHttpRequest(JS/React)分片上传大文件时浏览器崩溃的解决办法问询

问题根因
  • 现有实现会一次性将整个文件读入内存:调用reader.readAsArrayBuffer(file)会把完整的文件内容全量加载到内存中,文件越大内存占用越高,超过1G很容易触发浏览器内存限制直接崩溃
  • 使用了同步XHR请求:xhr.open('PUT', url, false)第三个参数为false代表同步请求,会阻塞浏览器主线程,上传过程中页面会完全卡死,甚至触发浏览器无响应提示
  • forEach搭配async的写法完全无效:所有分片上传请求会同时发起,大量请求同时持有分片内存,进一步加剧内存占用
优化实现方案

优化核心思路是不需要一次性读完整文件,利用File本身是Blob类型的特性直接分片切割后上传,同时控制并发数,使用异步请求避免阻塞主线程,修改后代码如下:

axios.post(`/URL_GOES_HERE`, { 
  name: file.name, 
  size: file.size, 
  md5, 
  extension: file.type.split('/')[1] 
}).then(async (response) => {
  const { chunks, status } = response.data;
  if (status !== 'uploading') return;

  // 可根据实际场景调整并发上限,避免请求过多占用内存
  const CONCURRENT_LIMIT = 3;
  let start = 0;
  // 生成分片上传任务队列
  const chunkTasks = chunks.map(({ materialId, size, index }) => {
    // 直接切割File,不需要提前读取全量文件
    const chunk = file.slice(start, start + size);
    start += size;
    return async () => {
      const url = `URL_FOR_EACH_CHUNK`;
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        // 第三个参数为true,使用异步请求不阻塞主线程
        xhr.open('PUT', url, true);
        xhr.setRequestHeader('Content-Type', 'application/octet-stream');
        xhr.setRequestHeader('Authorization', `Bearer TOKEN_GOES_HERE`);
        xhr.onload = () => xhr.status >= 200 && xhr.status < 300 ? resolve() : reject(xhr.status);
        xhr.onerror = reject;
        // 直接发送Blob分片,不需要额外转Uint8Array减少内存拷贝
        xhr.send(chunk);
      });
    };
  });

  // 控制并发执行
  const executing = [];
  for (const task of chunkTasks) {
    const p = task();
    executing.push(p);
    // 达到并发上限就等待任意任务完成再补入下一个任务
    if (executing.length >= CONCURRENT_LIMIT) {
      await Promise.race(executing);
      executing.splice(executing.indexOf(Promise.race(executing)), 1);
    }
  }
  // 等待所有剩余分片上传完成
  await Promise.all(executing);
  // 此处可补充全部分片上传完成后的后续逻辑
})
关键优化说明
  • 移除了全量读取文件的FileReader逻辑:Blob.slice(File继承自Blob)本身支持直接切割文件,不需要提前把整个文件加载到内存,浏览器会自动按需读取对应分片内容,内存占用可以稳定在和分片大小相近的量级
  • 全部改用异步XHR请求,不会阻塞主线程,上传过程中页面操作不会受到影响
  • 增加了并发数控制,默认同时上传3个分片,可根据业务场景灵活调整数值,避免同时发起几十上百个请求导致内存暴涨
  • 直接发送Blob类型的分片,不需要额外转成Uint8Array,减少不必要的内存拷贝

内容的提问来源于stack exchange,提问作者MatiN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 08:30:02