如何从 React 应用程序和 Web Worker 调用共享方法
How to call a shared method from a react app and a web worker
如何在 React 应用程序和 Web Worker 中引用实用程序 class?
这是一个简单的 create-react-app 演示了我的核心问题。 Web Worker 代码本身工作正常,它只是无法访问 Util class.
App.js
import React, { Component } from 'react';
import './App.css';
import Util from './Util.js'
import worker from './Util.worker.js';
import WebWorker from './WebWorker.js';
export default class App extends Component {
constructor(props) {
super(props);
this.util = new Util();
this.state = { something: "" };
}
componentDidMount() {
this.worker = new WebWorker(worker);
this.worker.addEventListener('message', e => {
this.setState({ something: e.data })
});
}
render() {
return (
<div className="App">
<p onClick={e => this.randomHandler()}>{this.util.DoSomething("hello")}</p>
<p>{this.state.something}</p>
</div>
);
}
randomHandler() {
console.log("err")
this.worker.postMessage(["cool"]);
}
}
Util.js
export default class Util {
DoSomething(x) {
return this.AnotherMethod(x) + "!";
}
AnotherMethod(x) {
return x;
}
}
WebWorker.js
export default class WebWorker {
constructor(worker) {
const code = worker.toString();
const blob = new Blob(['(' + code + ')()']);
return new Worker(URL.createObjectURL(blob));
}
}
Util.worker.js
export default () => {
self.addEventListener('message', function(e) { // eslint-disable-line no-restricted-globals
postMessage("How do I call Util.DoSomething() here?");
}, false);
}
这是我希望能够做到的。
var util = new Util();
postMessage(util.DoSomething(e.data));
通常情况下,Web Worker 是在文件路径上实例化的,但由于应用程序的编译方式,这不能很好地与 React 配合使用。这就是为什么几个来源建议序列化该方法并从中动态创建工作程序(这就是我正在做的)。
我试过将 class 的序列化实例和 class 本身都传递给工作人员,但没有成功(而且感觉很老套)。
我也试过在 Web Worker 中导入 Util class,但我只是收到引用错误,因为 WebWorker class 不处理导入。
有这方面经验的人可以指出我做错了什么吗?
不幸的是,答案是从 Create React App 中弹出配置。一旦 this pull request 被合并,我们就不需要这样做了。
运行 这些命令。注意弹出命令是不可逆的
npm run eject
npm install thread-loader
npm install worker-loader
将此添加到模块>规则>oneOf 部分的 webpack.config(开发和生产)。
{
test: /\.worker\.(js|jsx|mjs)$/,
include: paths.appSrc,
use: [
require.resolve('worker-loader'),
// This loader parallelizes code compilation, it is optional but
// improves compile time on larger projects
require.resolve('thread-loader'),
{
loader: require.resolve('babel-loader'),
options: {
// @remove-on-eject-begin
babelrc: false,
presets: [require.resolve('babel-preset-react-app')],
// @remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
highlightCode: true,
},
},
],
},
然后Util.worker.js变成这样:
import Util from './Util.js'
self.addEventListener('message', function(e) {
var util = new Util();
self.postMessage(util.DoSomething(e.data));
}, false);
而 App.js 变成这样:
import React, { Component } from 'react';
import './App.css';
import Util from './Util.js'
import Worker from './Util.worker.js';
export default class App extends Component {
constructor(props) {
super(props);
this.util = new Util();
this.state = { something: "" };
}
componentDidMount() {
this.worker = new Worker();
this.worker.onmessage = e => {
console.warn(e.data);
this.setState({ something: e.data });
}
}
render() {
return (
<div className="App">
<p onClick={e => this.randomHandler()}>{this.util.DoSomething("hello")}</p>
<p>{this.state.something}</p>
</div>
);
}
randomHandler() {
console.log("err")
this.worker.postMessage("cool");
}
}
如何在 React 应用程序和 Web Worker 中引用实用程序 class?
这是一个简单的 create-react-app 演示了我的核心问题。 Web Worker 代码本身工作正常,它只是无法访问 Util class.
App.js
import React, { Component } from 'react';
import './App.css';
import Util from './Util.js'
import worker from './Util.worker.js';
import WebWorker from './WebWorker.js';
export default class App extends Component {
constructor(props) {
super(props);
this.util = new Util();
this.state = { something: "" };
}
componentDidMount() {
this.worker = new WebWorker(worker);
this.worker.addEventListener('message', e => {
this.setState({ something: e.data })
});
}
render() {
return (
<div className="App">
<p onClick={e => this.randomHandler()}>{this.util.DoSomething("hello")}</p>
<p>{this.state.something}</p>
</div>
);
}
randomHandler() {
console.log("err")
this.worker.postMessage(["cool"]);
}
}
Util.js
export default class Util {
DoSomething(x) {
return this.AnotherMethod(x) + "!";
}
AnotherMethod(x) {
return x;
}
}
WebWorker.js
export default class WebWorker {
constructor(worker) {
const code = worker.toString();
const blob = new Blob(['(' + code + ')()']);
return new Worker(URL.createObjectURL(blob));
}
}
Util.worker.js
export default () => {
self.addEventListener('message', function(e) { // eslint-disable-line no-restricted-globals
postMessage("How do I call Util.DoSomething() here?");
}, false);
}
这是我希望能够做到的。
var util = new Util();
postMessage(util.DoSomething(e.data));
通常情况下,Web Worker 是在文件路径上实例化的,但由于应用程序的编译方式,这不能很好地与 React 配合使用。这就是为什么几个来源建议序列化该方法并从中动态创建工作程序(这就是我正在做的)。
我试过将 class 的序列化实例和 class 本身都传递给工作人员,但没有成功(而且感觉很老套)。
我也试过在 Web Worker 中导入 Util class,但我只是收到引用错误,因为 WebWorker class 不处理导入。
有这方面经验的人可以指出我做错了什么吗?
不幸的是,答案是从 Create React App 中弹出配置。一旦 this pull request 被合并,我们就不需要这样做了。
运行 这些命令。注意弹出命令是不可逆的
npm run eject
npm install thread-loader
npm install worker-loader
将此添加到模块>规则>oneOf 部分的 webpack.config(开发和生产)。
{
test: /\.worker\.(js|jsx|mjs)$/,
include: paths.appSrc,
use: [
require.resolve('worker-loader'),
// This loader parallelizes code compilation, it is optional but
// improves compile time on larger projects
require.resolve('thread-loader'),
{
loader: require.resolve('babel-loader'),
options: {
// @remove-on-eject-begin
babelrc: false,
presets: [require.resolve('babel-preset-react-app')],
// @remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
highlightCode: true,
},
},
],
},
然后Util.worker.js变成这样:
import Util from './Util.js'
self.addEventListener('message', function(e) {
var util = new Util();
self.postMessage(util.DoSomething(e.data));
}, false);
而 App.js 变成这样:
import React, { Component } from 'react';
import './App.css';
import Util from './Util.js'
import Worker from './Util.worker.js';
export default class App extends Component {
constructor(props) {
super(props);
this.util = new Util();
this.state = { something: "" };
}
componentDidMount() {
this.worker = new Worker();
this.worker.onmessage = e => {
console.warn(e.data);
this.setState({ something: e.data });
}
}
render() {
return (
<div className="App">
<p onClick={e => this.randomHandler()}>{this.util.DoSomething("hello")}</p>
<p>{this.state.something}</p>
</div>
);
}
randomHandler() {
console.log("err")
this.worker.postMessage("cool");
}
}