JavaScript is single-threaded. What does this mean and what is a thread?
A thread is an execution context, which is all the information a CPU needs to execute a stream of instructions. So normally, JavaScript applications are contained in one thread.
Cons?
Imagine that in your web app, you need to process a long task. The DOM, which is the web page in common language, is going to freeze because the interpreter needs to finish the task before moving to the next one. It can’t process two tasks at the same time, so when it finishes the long task, only then will it be able to update the DOM and come back to life. To avoid that, the solution is to use a web worker.
What is a web worker?
A web worker is a JavaScript script executed in the background independently. Web workers are often able to utilize multi CPUs.
In this case, we are going to see how to use a web worker in React.
Setup:
-
Install Node.js which gives us access to npm and npx: https://nodejs.org/en/download/
-
Generate a React project by running in the terminal:
npx create-react-app replace-me-with-the-name-of-the-app — template typescript
If the command doesn't work, please verify the version of Node and npm. You need to have Node >= 10.16 and npm >= 5.6 on your machine.
Let’s have fun.
To be able to communicate with the worker, we are going to use onMessage and postMessage().
Now we are going to write our Fibonacci function that will be executed by the web worker.
//fibo.worker.js
// eslint-disable-next-line import/no-anonymous-default-export
export default () => {
// eslint-disable-next-line no-restricted-globals
self.onmessage = (message) => {
const nbr = message.data;
var n1 = 0;
var n2 = 1;
var somme = 0;
for (let i = 2; i <= nbr; i++) {
somme = n1 + n2;
n1 = n2;
n2 = somme;
}
const result = nbr ? n2 : n1;
postMessage(result);
};
};
To make the linter happy, we need to add some lines.
// eslint-disable-next-line import/no-anonymous-default-export
// eslint-disable-next-line no-restricted-globals
Now we are going to write our Workerbuilder because after the build of WebPack, everything will be bundled as f18f83d0–6ed0–484e-86f1–6d1938793085. For example, in this case. And we will lose the link to the file.
//woker-builder.js
export default class WorkerBuilder extends Worker {
constructor(worker) {
const code = worker.toString();
const blob = new Blob([`(${code})()`]);
return new Worker(URL.createObjectURL(blob));
}
}
Now we have our worker and worker builder. Let’s use them.
import WorkerBuilder from './worker/woker-builder';
import Worker from './worker/fibo.worker';
instance = new WorkerBuilder(Worker);
We are going to add a button to be able to trigger the message for the worker, and we are going to add a listener to show the reply from the worker.
componentDidMount() {
instance.onmessage = (message) => {
if (message) {
console.log("Message from worker", message.data);
}
};
}
<button onClick ={() => instance.postMessage(5)}>
Send Message
</button>
The App.tsx should look like this:
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import WorkerBuilder from "./worker/woker-builder";
import FiboWorker from "./worker/fibo.worker";
const instance = new WorkerBuilder(FiboWorker);
class App extends Component {
componentDidMount() {
instance.onmessage = (message) => {
if (message) {
console.log("Message from worker", message.data);
}
};
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Web worker in React
</p>
<button
onClick={() => {
instance.postMessage(5);
}}
>Send Message</button>
</header>
</div>
);
}
}
export default App;
When we click on send message, the console should look like this.
If we go deeper into the console, in the sources tab, we can see in the top right we have two threads — the main and the fibo worker named f18f83d0–6ed0–484e-86f1–6d1938793085.
I hope you learned something from this article, thank you for your reading.