You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web Worker能否支持多事件响应?如何传递XHR请求进度至主线程?

Web Worker多事件支持与进度传递实现

当然没问题!Web Worker完全支持message、以及通过自定义消息模拟的progress类事件交互,而且你完全可以编写一个能响应多种不同需求的Worker脚本——核心思路就是在postMessage传递的消息里带上类型标识,让主线程能区分不同的消息用途。

先给你明确两个核心点:

  • Web Worker本身没有内置的progress事件,但我们可以在XHR请求的progress回调里,主动向主线程发送带进度标识的消息,实现进度同步。
  • 一个Worker可以处理多种逻辑,只要主线程和Worker约定好消息的类型字段(比如type: 'progress'或type: 'data'),就能分别响应不同的事件场景。

直接上可运行的示例代码

1. 主线程代码(页面脚本)

// 创建Worker实例
const geometryWorker = new Worker('geometry-worker.js');

// 监听Worker发来的所有消息,根据type区分处理
geometryWorker.onmessage = (e) => {
  const { type, data } = e.data;
  switch(type) {
    case 'progress':
      // 这里更新你的进度条或进度提示
      console.log(`加载进度:${data.totalPercent}%,当前文件:${data.fileName}(${data.filePercent}%)`);
      break;
    case 'data':
      // 处理你原本的Geometry数据(ArrayBuffer形式)
      const { normal, position, index } = data;
      console.log('收到Geometry数据,开始加载');
      // 这里写你原本的Geometry加载逻辑
      break;
    case 'error':
      console.error('加载出错:', data);
      break;
  }
};

// 监听Worker错误
geometryWorker.onerror = (error) => {
  console.error(`Worker出错:${error.message},行号:${error.lineno}`);
};

// 给Worker发指令,开始加载指定的JSON文件列表
geometryWorker.postMessage({
  type: 'load',
  files: ['normal.json', 'position.json', 'index.json']
});

2. Worker脚本(geometry-worker.js)

// 监听主线程的指令
self.onmessage = (e) => {
  const { type, files } = e.data;
  if (type === 'load') {
    // 批量加载多个JSON文件
    loadMultipleFiles(files);
  }
};

// 批量加载文件并统计总进度
async function loadMultipleFiles(fileList) {
  let totalCompletedFiles = 0;
  const totalFiles = fileList.length;
  
  for (const fileName of fileList) {
    try {
      const fileData = await loadSingleFile(fileName, (loaded, total) => {
        // 计算当前文件的加载进度,以及整体总进度
        const filePercent = Math.round((loaded / total) * 100);
        const totalPercent = Math.round(((totalCompletedFiles + loaded/total) / totalFiles) * 100);
        
        // 向主线程发送进度消息
        self.postMessage({
          type: 'progress',
          data: {
            fileName,
            filePercent,
            totalPercent,
            loaded,
            total
          }
        });
      });
      
      // 处理加载完成的JSON数据,转成ArrayBuffer(根据你的实际数据结构调整)
      const bufferData = convertToBuffer(fileData);
      // 向主线程发送最终的Geometry数据,转移ArrayBuffer所有权优化性能
      self.postMessage({
        type: 'data',
        data: bufferData
      }, [bufferData.normal, bufferData.position, bufferData.index]);
      
      totalCompletedFiles += 1;
    } catch (err) {
      self.postMessage({
        type: 'error',
        data: err.message
      });
    }
  }
}

// 单个文件加载函数,带进度回调
function loadSingleFile(fileName, progressCallback) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', fileName);
    xhr.responseType = 'json';
    
    // XHR原生progress事件,用来获取实时加载进度
    xhr.onprogress = (e) => {
      if (e.lengthComputable) {
        progressCallback(e.loaded, e.total);
      }
    };
    
    xhr.onload = () => {
      if (xhr.status === 200) {
        resolve(xhr.response);
      } else {
        reject(new Error(`加载${fileName}失败,状态码:${xhr.status}`));
      }
    };
    
    xhr.onerror = () => {
      reject(new Error(`加载${fileName}时发生网络错误`));
    };
    
    xhr.send();
  });
}

// 把JSON数组转换成ArrayBuffer(根据你的实际数据结构编写)
function convertToBuffer(jsonData) {
  // 示例:假设jsonData包含normal、position、index数组
  const normalBuffer = new Float32Array(jsonData.normal).buffer;
  const positionBuffer = new Float32Array(jsonData.position).buffer;
  const indexBuffer = new Uint16Array(jsonData.index).buffer;
  
  return {
    normal: normalBuffer,
    position: positionBuffer,
    index: indexBuffer
  };
}

代码关键点说明

  1. 消息类型约定:通过type字段区分进度、数据、错误三种消息,主线程和Worker靠这个字段判断该执行什么逻辑。
  2. XHR进度传递:在Worker里的XHRonprogress回调中,计算加载进度,通过postMessage把进度数据实时发给主线程。
  3. ArrayBuffer性能优化:传递ArrayBuffer时,使用postMessage的第二个参数(转移列表),把缓冲区所有权转移给主线程,避免内存拷贝,提升性能。

这样你的Worker既能完成原本的Geometry数据加载,又能把每个文件的加载进度实时传递回主线程啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:35:16