在 React 中创建一个 web worker
Creating a web worker inside React
我有一个用 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 应用程序中使用网络工作者的方法?
编辑:我在这里找到了解决方案:https://github.com/facebookincubator/create-react-app/issues/1277(post by yonatanmn)
是的,可以通过 custom-react-scripts
.
使用自定义 webpack 配置
如 issue 中所述,要在您现有的 create-react-app
项目中使用 custom-react-scripts
,您需要做的是:
从 package.json 中删除 反应脚本:
"devDependencies": {
"react-scripts": "0.6.1"
},
运行 npm install --save-dev *your-custom-react-scripts*
更详细的解释请看@kitze's article
和他自己的 custom-react-scripts
,包括对以下功能的内置支持:
- 装饰器
- babel-preset-stage-0
- 更少
- Sass
- CSS 个模块
- Sass 个模块
- 更少的模块
- 手写笔模块
正如我在上面问题的编辑中所写,我在这里找到了解决方案: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');
恭维 dnmh 的回答,如果您遇到 "this"、"self"、"window" 主题...
,this comment in the github issue 非常有效
在我的案例中,以下解决了我所有的麻烦:
这个文件你不用动,留着就好。
//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。将 package.json
中的 npm
脚本替换为:
"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
从 webpack 5 开始,您可以使用 web workers 而无需使用 worker-loader 或任何捆绑器 以简单的方式 , https://webpack.js.org/guides/web-workers/
我设法 运行 我的网络工作者以同样的方式。
在你要导入web worker的文件中
// here ./deep-thought.js is the path to the web worker
const worker = new Worker(new URL('./deep-thought.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);
};
在网络工作者文件中,
// just to show it supports importing files into web worker in generic way
import JSONstream from 'JSONStream';
self.onmessage = function (e) {
// worker code inside
// just to show it supports importing and using files into web worker in generic way
const jsonParser = JSONstream.parse();
}
我有一个用 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 应用程序中使用网络工作者的方法?
编辑:我在这里找到了解决方案:https://github.com/facebookincubator/create-react-app/issues/1277(post by yonatanmn)
是的,可以通过 custom-react-scripts
.
如 issue 中所述,要在您现有的 create-react-app
项目中使用 custom-react-scripts
,您需要做的是:
从 package.json 中删除 反应脚本:
"devDependencies": { "react-scripts": "0.6.1" },
运行
npm install --save-dev *your-custom-react-scripts*
更详细的解释请看@kitze's article
和他自己的 custom-react-scripts
,包括对以下功能的内置支持:
- 装饰器
- babel-preset-stage-0
- 更少
- Sass
- CSS 个模块
- Sass 个模块
- 更少的模块
- 手写笔模块
正如我在上面问题的编辑中所写,我在这里找到了解决方案: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');
恭维 dnmh 的回答,如果您遇到 "this"、"self"、"window" 主题...
,this comment in the github issue 非常有效在我的案例中,以下解决了我所有的麻烦:
这个文件你不用动,留着就好。
//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。将 package.json
中的 npm
脚本替换为:
"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
从 webpack 5 开始,您可以使用 web workers 而无需使用 worker-loader 或任何捆绑器 以简单的方式 , https://webpack.js.org/guides/web-workers/
我设法 运行 我的网络工作者以同样的方式。
在你要导入web worker的文件中
// here ./deep-thought.js is the path to the web worker
const worker = new Worker(new URL('./deep-thought.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);
};
在网络工作者文件中,
// just to show it supports importing files into web worker in generic way
import JSONstream from 'JSONStream';
self.onmessage = function (e) {
// worker code inside
// just to show it supports importing and using files into web worker in generic way
const jsonParser = JSONstream.parse();
}