Why?
Web Workers: A solution for overcoming JavaScript’s single-threaded limitations.
Running JavaScript tasks in background threads, separate from the main browser thread which is responsible for rendering the UI and handling user interactions.
So Its possible to run heavy task in multiple process and at the same time keep the ui responsive.
How?
The structure
Our Worker script (for example our-web-worker.js) A separate Script Which is responsible for maintaining the background task
Since the wokerscript runs seperately from our main website script so we need to set a communication between web-worker script and our main browser script.
postMessage: It used for send message in both sides. We can send instruction: the variable and other data to the worker script. and the worker script can send the result with it
onmessage: When one script( main script or worker script) postMessage other script get that message with onmessage.
Example
our-web-worker.js
self.onmessage = function(event) {
const n = event.data;
const result = calculateFibonacci(n);
self.postMessage(result);
};
function calculateFibonacci(n) {
var fib = [0, 1];
for (let i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
//return fib[n];
}
Our web-worker.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Worker Example</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.5.0/semantic.min.css">
</head>
<body>
<div class="ui container">
<h2 class="ui header">Fibonacci Sequence Calculator</h2>
<div class="ui action input">
<input type="number" id="numberInput" placeholder="Enter a number...">
<button class="ui button" onclick="calculateWithWorkers()">Calculate with Workers</button>
<button class="ui button" onclick="calculateWithoutWorker()">Calculate without Worker</button>
</div>
<div id="resultWorkers" class="ui message hidden"></div>
<div id="resultWithoutWorker" class="ui message hidden"></div>
</div>
<script>
function calculateWithWorkers() {
const number = parseInt(document.getElementById('numberInput').value);
const startTime = performance.now();
const workers = [];
const workerResults = [];
const numWorkers = 4;
const range = Math.floor(number / numWorkers);
for (let i = 0; i < numWorkers; i++) {
const worker = new Worker('our-web-worker.js');
worker.onmessage = function(event) {
workerResults.push(event.data);
if (workerResults.length === numWorkers) {
const result = workerResults.reduce((acc, val) => acc + val, 0);
displayResult('resultWorkers', result, startTime);
workers.forEach(worker => worker.terminate());
}
};
const start = i * range + 1;
const end = (i + 1) * range;
worker.postMessage({ start, end, number });
workers.push(worker);
}
}
function calculateWithoutWorker() {
const number = parseInt(document.getElementById('numberInput').value);
const startTime = performance.now();
const result = calculateFibonacci(number);
displayResult('resultWithoutWorker',result, startTime);
}
function calculateFibonacci(n) {
var fib = [0, 1];
for (let i = 2; i <= n; i++) {
fib[i] = fib[i - 1] + fib[i - 2];
}
//return fib[n];
}
function displayResult(elementId, result='', startTime) {
const resultElement = document.getElementById(elementId);
const elapsedTime = (performance.now() - startTime).toFixed(2) + ' milliseconds';
resultElement.classList.remove('hidden');
resultElement.textContent = `Result: (Time taken: ${elapsedTime})`;
}
</script>
</body>
</html>
we applied 4 worker. To test the code run in a server.
If you test this directly in the browser you may face the security issue. To overcome this
setup a simple server for testing.
If you are on linux you can use python built in server
make sure terminal is open from your code directory.
python3 -m http.server
Then go to http://localhost:8000 and click on the web-worker.html
Try larger number for example 5 million to check the result in the user input. As we are testing the worker with Fibonacci number