将 Web Workers 与 React 和 Webpack 5 结合使用

Th0*_*gal 10 javascript web-worker reactjs webpack

我已经尝试将 Web Workers 与 React 一起使用几天了,但遇到了一些问题。

我从使用 webpack 4 的 create-react-app 开始。我可以使用本教程使用 Web Worker: https: //javascript.plainenglish.io/web-worker-in-react-9b2efafe309c,它以这种方式加载 WebWorker:

export default class WorkerBuilder extends Worker {
  constructor(worker) {
    const code = worker.toString();
    const blob = new Blob([`(${code})()`]);
    return new Worker(URL.createObjectURL(blob));
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我需要使用我的工作人员(d3-delaunay)中的一个库,当我尝试这样做时,webpack 给了我一个错误(我认为它改变了它的路径)。

我听说过worker-loader,并且了解到它已被弃用,因为Web Worker导入现在是在webpack 5中内置的。

我将我的应用程序更新到了 WebPack 5(如 create-react-app wiki 中所述),这并不容易,因为我的很多依赖项都损坏了。

但是当我尝试加载我的 WebWorker 时,如下所述: https: //webpack.js.org/guides/web-workers/ 这根本不起作用(没有错误)。

这是我的代码:

console.log("hello");
const worker = new Worker(new URL('./world.worker.js', import.meta.url));
worker.postMessage({
    question:
        'The Answer to the Ultimate Question of Life, The Universe, and Everything.',
});
worker.onmessage = ({ data: { answer } }) => {
    console.log(answer);
};
console.log("world");
Run Code Online (Sandbox Code Playgroud)

还有我的 world.worker.js:

import { Delaunay } from "d3-delaunay";

// eslint-disable-next-line import/no-anonymous-default-export
export default () => {
    // eslint-disable-next-line no-restricted-globals
    self.onmessage = (message) => {
        console.log("yolo");
    };
};
Run Code Online (Sandbox Code Playgroud)

但我唯一的输出是:

hello
world
Run Code Online (Sandbox Code Playgroud)

我的工人似乎没有工作。

小智 10

我终于弄清楚了,我也遇到了同样的问题。最大的问题是您不应该在 Web Worker 中使用导出默认值。这是我让它发挥作用的方法。

您需要使用 React.useMemo 实例化工作线程。这样就只创建了一名工人。

const worker = React.useMemo(() => new Worker(new URL('./world.worker.js', import.meta.url)), []);
Run Code Online (Sandbox Code Playgroud)

要获得响应,您需要知道工作对象何时更新。为此,您可以使用 React.useEffect。

React.useEffect(() => {
  worker.onmessage = ({ data: { answer } }) => {
    console.log(answer);
    return () => worker.terminate();
  }
}, [worker]);
Run Code Online (Sandbox Code Playgroud)

最后,您的 world.worker.js 文件有两个问题。第一个是它实际上不返回任何内容。您需要添加对 postMessage 的调用。我很难解决的第二个问题是,您不应该将函数包装在导出默认值中。我认为这是因为 webpack 会为你包装它。请参阅下面的正确 world.worker.js 代码。

import { Delaunay } from "d3-delaunay";

self.onmessage = ({ data: { question } }) => {
  postMessage({
    answer: 42,
  });
};
Run Code Online (Sandbox Code Playgroud)


小智 -1

要在worker中使用es6模块,您需要使用以下语法以脚本模式加载它:

new Worker('worker-path.js', {type: 'module'})
Run Code Online (Sandbox Code Playgroud)