【问题标题】:Fetch in a Web Worker using React使用 React 获取 Web Worker
【发布时间】:2018-09-17 16:57:02
【问题描述】:

我有一个 React 页面,它要求用户输入一些信息并从 API 返回 JSON 对象数组。

查询会返回一个很大的结果,导致页面在加载 fetch 时冻结,所以我想使用 web worker 来分离线程并添加一个加载轮来让用户知道网站没有崩溃.

我目前有我的网络工作者使用此代码:

工人代码

const self = this;

export default () => {
    self.addEventListener('message', e => {
        if (!e) return;
        let query = e.data;
        let res = null;

        fetch(`https://statsapi.web.nhl.com/api/v1/schedule?startDate=${query}&endDate=${query}`)
        .then(response => {
            return response.json();
        })
        .then(function(_ref) {
            postMessage(_ref);
        });
    });
}; 

这只是一个示例 API,但真正的 API 结果会更大并且需要更长的时间来加载。

我也使用function(_ref)而不是({ data }) =>,因为当通过babel处理时,({ data }) =>会在没有通过ref的数据访问器时变成_ref.data,而_ref用于返回数组。

我的代码在这样的网络工作者类中实现:

工人构造函数

export default class WebWorker {
    constructor(worker) {
        const code = worker.toString();
        const blob = new Blob(['(' + code + ')()'], { type: 'text/javascript' });
        return new Worker(URL.createObjectURL(blob));
    }
}

我这样称呼另一个班级的网络工作者:

Web Worker 创建

componentDidMount = () => {
    this.worker = new WebWorker(worker);
}

getInfo = () => {
    this.worker.postMessage(this.state.query);

    this.setState(prevState => ({
        ...prevState,
        open: true
    }), () => {
        this.worker.addEventListener('message', (event) => {
            const res = event.data;
            this.setState({
                results: res,
                open: false
            });
        });
    });
}

我遇到的问题是当我尝试像我一样调用它时,网络工作者似乎没有在另一个线程上处理。即使网络工作者正在获取数据,页面仍然会冻结,因为它在冻结后仍然正确设置状态。

我是网络工作者的新手,所以我是否遗漏了一些可以让它工作的东西,或者是否有不同的方式来使用网络工作者和获取?

【问题讨论】:

  • 如果 JSON 数据很多,您可能会遇到序列化/反序列化的成本,因为这是一个 CPU 密集型操作。
  • (遗憾的是,共享数组缓冲区仅适用于 Chrome。caniuse.com/#feat=sharedarraybuffer
  • 你有没有机会为此使用 Create React App? CRA 在使用网络工作者时存在已知问题。
  • 是的,我正在使用 Create React App

标签: javascript reactjs fetch web-worker


【解决方案1】:

如果您的页面变得无响应,则表明主处理线程正受到 CPU 密集型操作的影响。 I/O 绑定操作(例如从 URL 获取)不会影响页面的响应能力,除了响应中的一些解析开销。因此,worker 的最佳用法是在不同的线程上执行 CPU 密集型操作。将 I/O 操作转移到工作人员身上,您获得的性能非常少(如果有的话)。

很可能是您的渲染逻辑或数据处理导致事情挂起,而不是网络请求处理。

【讨论】:

    【解决方案2】:

    您首先需要确定问题所在。 API 的响应可能很好,但是如果您正在对数以万计的对象进行“处理”——循环、排序、映射等——(或渲染数千个元素),那么您的页面性能可能会受到很大影响。

    像分页这样简单的东西可能是一切的答案。

    【讨论】:

    • 做“东西”的问题是获取应该需要大约 5 秒,当我点击加载时,页面变得无响应大约 6 秒,我在控制台中设置断点以查看在哪里代码是,看看是否可能都是渲染问题,但是由于页面无响应,断点在 addEventListener 处被命中
    • 那么你可能又遇到了另一个问题。只是粗略地看一下您的代码 - 您在 getInfo 中的每个 setState 之后向您的工作人员添加一个事件侦听器可能会很可怕 - 您是否多次调用 getInfo ?如果是这样,那么您将不止一次添加事件侦听器。
    • 我确实将它绑定到一个按钮,当用户输入查询所需的信息时,它会调用该函数。除了那个按钮,别无他处。
    • 如果还没有,那以后会咬你的。您不想每次都添加侦听器,您只想添加一次侦听器(否则多个查询将导致添加多个事件侦听器,这意味着在每个单独的查询之后,您的侦听器回调将被触发多次,而不仅仅是一次如你所愿)。但是,这与您当前的问题是分开的。
    • 好的,不过谢谢你的提示,我会修改它,所以它只存在一个实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 2017-09-06
    • 2018-05-08
    相关资源
    最近更新 更多