在 React 中创建 Web Worker

IT技术 reactjs webpack web-worker create-react-app
2021-04-09 01:49:07

我有一个用 create-react-app 创建的 React 应用程序,但没有弹出。我正在尝试使用网络工作者。我试过 worker-loader 包(https://github.com/webpack-contrib/worker-loader)。

如果我尝试开箱即用的 worker-loader ( import Worker from 'worker-loader!../workers/myworker.js';),我会收到错误消息,告诉我 Create React App 不支持 Webpack 加载器,我已经知道了。

解决方案是弹出应用程序(我不想这样做)并编辑 webpack.config.js 还是有其他方法可以在 React 应用程序中使用 Web Worker?

编辑:我在这里找到了解决方案:https : //github.com/facebookincubator/create-react-app/issues/1277(由 yonatanmn 发布)

4个回答

正如我在上面问题的编辑中所写的那样,我在这里找到了解决方案:https : //github.com/facebookincubator/create-react-app/issues/1277

这是一个工作示例:

// worker.js
const workercode = () => {

    self.onmessage = function(e) {
        console.log('Message received from main script');
        var workerResult = 'Received from main: ' + (e.data);
        console.log('Posting message back to main script');
        self.postMessage(workerResult);
    }
};

let code = workercode.toString();
code = code.substring(code.indexOf("{")+1, code.lastIndexOf("}"));

const blob = new Blob([code], {type: "application/javascript"});
const worker_script = URL.createObjectURL(blob);

module.exports = worker_script;

然后,在需要使用 web worker 的文件中:

import worker_script from './worker';
var myWorker = new Worker(worker_script);

myWorker.onmessage = (m) => {
    console.log("msg from worker: ", m.data);
};
myWorker.postMessage('im from main');
问题是您无法将任何函数导入 blob。
2021-05-25 01:49:07
意外使用“自我”无限制全局变量
2021-06-19 01:49:07

是的,可以通过使用自定义 webpack 配置custom-react-scripts

custom-react-scripts在您现有的create-react-app项目中使用,如本期所述,您需要做的是:

  • 从 package.json 中删除react-scripts:

    "devDependencies": {
        "react-scripts": "0.6.1"
    },
    
  • npm install --save-dev *your-custom-react-scripts*

有关更详细的解释,请查看@kitze 的文章 和他自己的文章custom-react-scripts,其中包括对以下功能的内置支持:

  • 装饰器
  • babel-preset-stage-0
  • 较少的
  • 萨斯
  • CSS module
  • Sass module
  • 更少的module
  • 手写笔module
谢谢你的提示。知道这样的事情是可能的很方便。与此同时,我找到了一个更简单的解决方案(请参阅上面的编辑)。
2021-06-19 01:49:07

赞美 dnmh 的回答,如果您遇到“this”、“self”、“window”主题的问题,那么github 问题中的此评论非常有效……

在我的情况下,以下解决了我所有的麻烦:

你不需要接触这个文件,只要保留它。

//WebWorkerEnabler.js
export default class WebWorkerEnabler {
    constructor(worker) {
         let code = worker.toString();
         code = code.substring(code.indexOf("{") + 1, code.lastIndexOf("}"));

         const blob = new Blob([code], { type: "application/javascript" });
         return new Worker(URL.createObjectURL(blob));
    }
}

这是您运行后台任务的地方

// WebWorker.js
export default function WebWorker(args) {
    let onmessage = e => { // eslint-disable-line no-unused-vars
         // THIS IS THE PLACE YOU EMBED YOUR CODE THAT WILL RUN IN BACKGROUND        
         postMessage("Response");
    };
}

这是 WebWorker 与其余代码的连接。您从下面的componentDidMount函数向 WebWorker 发送和接收数据

//BackgroundTaskRunner.js
import * as React from 'react';
import WebWorkerEnabler from './WebWorkerEnabler.js';
import WebWorker from './WebWorker.js';
const workerInstance = new WebWorkerEnabler(WebWorker);
export default class BackgroundTaskRunner extends React.Component {
    componentDidMount(){
        workerInstance.addEventListener("message", e => {
            console.log("Received response:");
            console.log(e.data);
        }, false);
        workerInstance.postMessage("bar");
    }
    render() {
        return (
                <React.Fragment>
                    {"DEFAULT TEXT"}
                </React.Fragment>
        );
    }
}

按照以下步骤将您的工作文件添加到您的create-react-app项目中。

1.安装这三个包:

$ yarn add worker-plugin --dev
$ yarn add comlink
$ yarn add react-app-rewired --dev

2.覆盖webpack配置:

在您的项目root目录中创建一个config-overrides.js包含以下内容文件:

const WorkerPlugin = require("worker-plugin");

module.exports = function override(config, env) {
    //do stuff with the webpack config...

    config.plugins = [new WorkerPlugin({ globalObject: "this"}), ...config.plugins]
    return config;
}

3. 将npm里面package.json脚本替换为:

"start": "react-app-rewired start",
"build": "react-app-rewired build",

4. 创建两个文件以测试您的配置:

worker.js

import * as Comlink from "comlink";

class WorkerWorld {
  sayHello() {
    console.log("Hello! I am doing a heavy task.")
    let numbers = Array(500000).fill(5).map(num => num * 5);
    return numbers;
  }
}

Comlink.expose(WorkerWorld)

use-worker.js

import * as Comlink from "comlink";

const initWorker = async () => {
    const workerFile = new Worker("./worker", { name: "my-worker", type: "module" });
    const WorkerClass = Comlink.wrap(workerFile)

    const instance = await new WorkerClass();
    const result = await instance.sayHello();
    console.log("Result of my worker's computation: ", result);
}
initWorker()

5. 查看输出:

$ yarn start