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

React v18中Shared Worker无法正常工作的问题求助

React 18 中 Shared Worker 实现问题解决

问题背景

尝试多种方式编写fibWorkerShared.js文件,均无法在React 18中正常运行:

  • 首次尝试直接定义全局onconnect函数,React编译报错'onconnect'未定义
  • 尝试用self.addEventListener并导出函数,编译报错意外使用'self'
  • 尝试直接用addEventListener导出函数,编译报错意外使用'addEventListener'
  • 定义独立onconnect函数,无编译错误但Worker无法收发消息,事件未被触发

初始化Shared Worker的代码:

useEffect(() => {
    console.log("useEffect [] for shared Worker");

    if (!sharedWorker) {
      sharedWorker = new SharedWorker(
        new URL("./fibWorkerShared.js", import.meta.url)
      );

      sharedWorker.port.postMessage("Hello worker!");

      sharedWorker.port.onmessage = function (e) {
        console.log("First app", "<<<", e.data);
      };
    }
  }, []);

核心原因

React的打包工具(如Vite、Create React App)会默认将所有JS文件当作ES模块处理,而Shared Worker的运行环境是独立的全局上下文,并非模块环境。模块式写法(如export default)会触发编译错误,全局变量也会被打包工具隔离,导致事件监听器无法被识别。

解决方案

1. 正确编写Shared Worker文件

直接在全局作用域下编写代码,不使用ES模块语法:

// fibWorkerShared.js
onconnect = (e) => {
  const port = e.ports[0];
  
  // 发送初始化消息
  port.postMessage("I'm alive!");

  // 监听主线程消息并回复
  port.onmessage = (msgEvent) => {
    console.log("Worker received:", msgEvent.data);
    port.postMessage("I'm good!");
  };

  // 部分浏览器需手动启动端口(现代浏览器大多自动处理)
  port.start();
};

2. 配置打包工具,避免将Worker文件当作模块处理

根据使用的打包工具做对应配置:

  • Vite:导入Worker时添加?shared后缀,Vite会自动识别为Shared Worker并正确处理:
    // 初始化代码修改为
    sharedWorker = new SharedWorker(
      new URL("./fibWorkerShared.js?shared", import.meta.url)
    );
    
  • Create React App:将fibWorkerShared.js放在public目录下,通过绝对路径引用:
    sharedWorker = new SharedWorker("/fibWorkerShared.js");
    
    注:public目录下的文件不会被编译,直接作为静态资源访问。

3. 主线程代码优化

添加端口启动逻辑及组件卸载时的清理:

useEffect(() => {
    console.log("useEffect [] for shared Worker");

    if (!sharedWorker) {
      sharedWorker = new SharedWorker(
        new URL("./fibWorkerShared.js?shared", import.meta.url)
      );

      // 启动端口(可选,建议添加)
      sharedWorker.port.start();

      sharedWorker.port.postMessage("Hello worker!");

      sharedWorker.port.onmessage = function (e) {
        console.log("First app", "<<<", e.data);
      };

      // 组件卸载时关闭端口
      return () => {
        sharedWorker.port.close();
      };
    }
  }, []);

验证标准

运行项目后,打开浏览器控制台:

  1. 能接收到Worker发送的I'm alive!消息
  2. 主线程发送Hello worker!后,能收到Worker回复的I'm good!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:45:13