Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch in a Web Worker using React

I have a React page that asks for a user input for some info and returns an array of JSON objects from an API.

The query can return a large result causing in the page to freeze on loading the fetch, so I wanted to use a web worker to separate the threads and add a loading wheel to allow the user to know the site hasn't crashed.

I currently have my web worker with this code:

Worker Code

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);
        });
    });
}; 

This is just an example API, but the real API result would be much larger and take a longer time to load.

I am also using function(_ref) instead of ({ data }) => because when processed through babel, ({ data }) => would be turned into _ref.data when there is no data accessor through ref, and _ref works at returning the array.

I have my code implemented in a web worker class like such:

Worker Constructor

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

I call the webworker in another class as such:

Web Worker Creation

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
            });
        });
    });
}

The issue I have been running into is when I attempt calling it like I am, the web worker doesn't seem to be processing on another thread. The page still freezes even though the web worker is getting the data, as it still sets the state correctly after freezing.

I am new to web workers so is there something that I am missing that would allow it to work or would there be a different way of using a web worker with a fetch?

like image 367
Sean Avatar asked Sep 17 '18 16:09

Sean


People also ask

Can you use fetch in a web worker?

Comlink-fetch allows you to use Fetch in a web worker that is exposed through Comlink.

Does React use web workers?

web workers help us to solve this problem, making our application dynamic so it loads faster. In this tutorial, we'll learn how to use web workers in a React application. We'll also learn how to use the useReducer Hook within a web worker with useWorkerizedReducer . Let's get started!

How do I use Axios with WebWorker?

You can't use axios inside the worker because the blob that's created behind the scenes to load the worker. js runs in a different context than your main. js . In order for axios to work, you would have to setup a new webpack bundler to just bundle the worker by itself.

How do I create a web worker in React?

The first thing to do is to create the web worker using the Worker constructor. Then inside our button's event listener, we send a number to the worker using worker. postMessage({ num }) . After that, we set a function to listen for errors in the worker.


1 Answers

If your page is becoming unresponsive, that's an indicator that the main processing thread is being impacted by CPU-bound operations. I/O-bound operations, like fetching from a URL, would not impact your page's responsiveness, except for a bit of parsing overhead from the response. Therefore, the best usage of workers is to do CPU-intensive operations on a different thread. You gain very little (if anything) performance-wise moving I/O operations to workers.

Most likely, your rendering logic or data processing is what's causing things to hang, not the network request processing.

like image 129
Jacob Avatar answered Oct 22 '22 02:10

Jacob