Search code examples
javascriptreactjsfetchweb-worker

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?


Solution

  • 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.