如何从React应用和网络工作者中调用共享方法

时间:2018-09-30 23:59:30

标签: reactjs ecmascript-6 web-worker

如何在React应用程序和Web Worker中引用实用程序类?

这是一个简单的 create-react-app ,它展示了我的核心问题。网络工作者代码本身可以正常工作,只是无法访问Util类。

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中不能很好地发挥作用。这就是为什么几个消息源建议序列化该方法并从中动态创建工作程序(这就是我正在做的事情)。

我尝试过将类的序列化实例和类本身传递给工作程序,但是没有奏效(感觉很黑)。

我也尝试过在Web worker中导入Util类,但由于WebWorker类不处理导入,因此我只收到参考错误。

在这方面有经验的人能指出我做错了吗?

1 个答案:

答案 0 :(得分:0)

不幸的是,答案是从Create React App弹出配置。 this pull request合并后,我们就不需要这样做了。

运行这些命令。请注意,弹出命令是不可逆的。

npm run eject
npm install thread-loader
npm install worker-loader

将其添加到module> rules> 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");
    }
}