DEV Community

Cover image for Web Worker in React: A step-by-step guide
Harshal Suthar
Harshal Suthar

Posted on

Web Worker in React: A step-by-step guide

Understanding web worker in React is entirely dependent on the idea of JavaScript’s code execution. So, before you begin, you should understand how JavaScript code is executed.

JavaScript is single-threaded in nature. That is when one code thread completes its execution, the next one starts, and so on. This eventually leads to long delays and procedures becoming stalled. If one of the several threads has to be performed as soon as possible because subsequent processes rely on it, the app's performance will suffer as a result. This is where web workers come into play to alleviate such difficulties.

Web workers offer multi-threaded capability in JavaScript development. Furthermore, it removes the need for extended delays for process execution, making the app's performance quicker and smoother.

Image description

C#, Java, C++, and Emerald are some examples that offer parallel programming features and contribute to smoother functionality.

Let’s learn how to use web worker in React

What is a Web Worker?

A Web Worker is a feature of React.js that allows JavaScript code to execute in a separate background thread, freeing up the main thread to handle user interactions and refresh the UI.

Web Workers are commonly used to perform computationally intensive tasks such as image processing or complex calculations, without blocking the user interface.

In React, Web Workers can be created using the Worker API, which is a standard API provided by modern browsers. The Worker API allows you to create a new Web Worker instance from a JavaScript file, which can then be used to execute code in a separate thread.

To use a Web Worker in React, you typically create a new Worker instance in your component's componentDidMount lifecycle method, passing in the path to the JavaScript file that contains the worker code.

You can then send messages to the worker using the postMessage method and receive messages back from the worker using theonmessageevent handler.

How a "Web Worker API" interacts between the main thread and the worker thread?

Communication between the worker thread and the main thread occurs via the React Web Workers API in the following way.

Step – 1: Work instance initiation and passing the path of a worker script..

Step – 2: The main thread will use postMessage() to deliver a message for connection initiation, while the worker thread will wait for that message using onmessage ().

Step – 3: When the worker thread delivers a message usingpostMessage, the main thread will receive a message usingonmessage.

Step – 4: In the event of an error, there is an instance named oneerrorcall-back. It will capture errors from the worker thread.

Image description

How to use Web Worker in React?

Let’s understand web workers practically with an example.

Here, we will create a new Web Worker instance in our component’s constructor, passing the path to the App.js file. We then listen for messages from the worker in the handleCalculate method and send a message to the worker when the component is mounted using the postMessage method.

First, we will create a loop executer for num, then we will pass the number in the input field, and on the button click we will iterate the loop. On the iteration, we will display the calculated number message loaded on the page. Web Workers is an attempt to bring multi-threaded behavior to JavaScript.

App.js

    import React from 'react'
    import { Component } from 'react'
    class App extends Component {
      constructor() {
        super()
        this.state = {
          num: '',
          result: '',
          loadingMessage: ''
        }
        this.handleCount = this.handleCount.bind(this)
        this.handleCalculate = this.handleCalculate.bind(this)
      }

      handleCount(e) {
        this.setState({
          num: e.target.value
        })
      }
      handleCalculate() {
        const { num } = this.state
        let result = 0;
        for (let i = 1; i <= num; i++) {
          this.setState({
            loadingMessage: `Loaded ${i} / ${num}`
          })
          for (let j = 0; j < i; j++) {
            result++
          }
        }
        this.setState({
          result
        })
      }
      render() {
        return (

Enter fullscreen mode Exit fullscreen mode

We've used a number for the input box and a loadingMessage to display previously loaded numbers. When we enter a small range, it will show normally without interrupting the page's Interface. The result is as follows:

Image description

But, when we input a lengthy value for the iterating loop, the page UI is blocked. After a while, the page will stop responding. Here, we placed 500000000 into the text field; after a while, it will display the unresponsive page option. The result is shown below.

Image description

Now, we are going to do the same task using the web worker in React.

App.js

        import React from 'react'
        import { Component } from 'react'
        import workerScript from './Worker'

        import React from 'react'
        import { Component } from 'react'
        import workerScript from './Worker'

        class App extends Component {
          constructor() {
            super()
            this.state = {
              num: '',
              result: '',
              loadingMessage: ''
            }
            this.handleCount = this.handleCount.bind(this)
            this.handleCalculate = this.handleCalculate.bind(this)
          }

          componentDidMount() {
            this.worker = new Worker(workerScript)
            this.worker.addEventListener('message', e => {
              const type = e.data.type;
              if (type === 'loading') {
                const { i, num } = e.data;
                this.setState({
                  loadingMessage: `Loaded ${i} / ${num}`
                })
              }
              else {
                const { result } = e.data;
                this.setState({
                  result
                })
              }
            })
          }
          handleCount(e) {
            this.setState({
              num: e.target.value
            })
          }
          handleCalculate() {
            const { num } = this.state
            this.worker.postMessage(num)
          }
          render() {
            return (

Enter fullscreen mode Exit fullscreen mode

In this app component, we have imported the worker component and in the calculate method, we pass the number from the worker.js file. Whatever login we wrote on the button click event before the worker, we must now implement it in the worker file.

Worker.js

    const loopworker = () => {
        onmessage = (e) => {
            const num = e.data;
            let result = 0;
            for (let i = 1; i <= num; i++) {
                const data = { type: 'loading', i, num }
                postMessage(JSON.parse(JSON.stringify(data)))
                for (let j = 0; j < i; j++) {
                    result++;
                }
            }
            const data = {
                type: 'result',
                result
            }
            postMessage(JSON.parse(JSON.stringify(data)))
        }
    }

    let code = loopworker.toString()
    code = code.substring(code.indexOf("{") + 1, code.lastIndexOf("}"))
    const blob = new Blob([code], { type: 'application/javascriptssky' })
    const workerScript = URL.createObjectURL(blob)
    module.exports = workerScript;

Enter fullscreen mode Exit fullscreen mode

Let’s understand some of the crucial keywords that we used above.

Self:

Here, 'self' is guaranteed to link to a ServiceWorkerGlobalScope that contains attributes like clients, registrations or caches, and other event handlers. Nonetheless, it adheres to the same dynamic binding rules as the rest of the JavaScript environment. It doesn't matter if you remember it all the time, but use self when you wish to expressly refer to the global context.

e.data:

Any values passed from the app component will be accessed in the e.dataobject.

PostMessage:

To communicate with workers, the postMessage is used.

This brings us to the end of this blog. We hope you found this React.js tutorial useful. Please check our latest update for more articles like this.

React Web worker: Conclusion

Webworker in React is an important topic for React developers since it allows them to run multi-threaded programs. Understanding web workers in React.js is solely based on the JavaScript code execution concept. Hence, before you start, you should grasp how JavaScript code works. JavaScript is a single-threaded language. Web workers enable multi-threaded JavaScript programming. Additionally, it eliminates the need for lengthy pauses in process execution, resulting in faster and smoother app performance.

This blog has covered the fundamentals of web workers, how their API communicates with the main thread and worker thread, and a practical demonstration of how to use web worker with React.

Top comments (1)

Collapse
 
tracygjg profile image
Tracy Gilmore • Edited

Hi Harshal, Good article of an underutilised feature of modern browsers.
Here are a few minor comments to improve you post.

  1. Use syntax highlighting to improve code readability. dev.to/hoverbaum/how-to-add-code-h...
  2. There are a few typos: theonmessageevent, usingonmessage, usingpostmessage, oneerrorcall-back.
  3. Your first code example appears to be truncated and incomplete.
  4. It would be good to see an example using functional components in place of classical. Best regards.