What is Web Worker API?
Web Worker API is a JavaScript web API for running multiple tasks simultaneously without affecting the performance of the apps.
Why Web Worker API?
JavaScript is single-threaded which means it has one main thread of execution. When executing scripts, the app become unresponsive until the scripts is finished. For example, when executing a function that takes one minute, during the execution time, clicking buttons and selecting text become unresponsive. This problem can be solved by executing that function in a separate thread using a web worker.
Get Started
Now we have a better understanding of what web worker is, what it is capable of, and why we might use it. Let's get started with the API.
Create a web worker
var worker = new Worker(url, options);
The first argument is the URL of the JavaScript file. It must obey the same-orgin policy. It also take a second optional argument. For more information, please visit mozilla .
Send data to a web worker
worker.postMessage(data, [transfer]);
The first argument can be any JavaScript object. It also take a second optional argument. For more information, please visit mozilla .
Receive data from a web worker
worker.addEventListener('message', function (e) {
// e.data
});
Terminate a web worker
worker.terminate();
In a web worker file
Send data to the owner
self.postMessage(data);
Receive data from the owner
self.addEventListener('message', function (e) {
// e.data
});
Close the process
self.close();
Example
In this example, we are going to create an app that generate an random number (from 50000 to 100000) and get the generated number nth of prime number.
Create the User Interface
Create a html file named nth-prime.html
.
<!DOCTYPE html>
<html lang="en">
<head>
<title>nth-prime</title>
<style type="text/css">
#nthPrimeProgress {
min-height: 20px;
height: 20px;
background: #1da8e8;
width: 0;
}
</style>
</head>
<body>
<div>
<span>Random Number: </span>
<span id="randNum"></span>
</div>
<button id="randNumBtn">Generate</button>
<br />
<br />
<div>
<span id="randNth"></span>
<span>Nth-Prime Number: </span>
<span id="nthPrime"></span>
</div>
<div id="nthPrimeProgress"></div>
<button id="nthPrimeBtn">Get Prime</button>
<script type="text/javascript" src="nth-prime.js"></script>
</body>
</html>
Create a web worker
Create a JavaScript file named nth-prime-worker.js
.
self.addEventListener('message', onMessage);
/**
* Event listener for message
* @param {Event} e
* @time complexity: O(n * sqrt(n))
* @space complexity: O(1)
*/
function onMessage(e) {
if (e.data.action === 'getNthPrime') {
const nthPrime = getNthPrime(e.data.nth);
self.postMessage({
action: 'nthPrime',
prime: nthPrime
});
}
}
/**
* Get nth prime number
* @param {Number} n
* @return {Number}
* @time complexity: O(n * sqrt(n))
* @space complexity: O(1)
*/
function getNthPrime(n) {
let prime = null,
num = 3,
i = 0;
while (i < n) {
if (isPrime(num)) {
prime = num;
i++;
self.postMessage({
action: 'nthPrimeProgress',
prime: num,
progress: i / n
});
}
num++;
}
return prime;
}
/**
* Check whether or not the number is prime
* @param {Number} n
* @return {Boolean} true if the number is prime, otherwise false
* @time complexity: O(sqrt(n))
* @space complexity: O(1)
*/
function isPrime(n) {
if (n < 3) {
return false;
}
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
return false;
}
}
return true;
}
Create a JavaScript file for the UI
Create another JavaScript file named nth-prime.js
.
(function () {
const randNumTxt = document.querySelector('#randNum'),
randNumBtn = document.querySelector('#randNumBtn'),
randNthTxt = document.querySelector('#randNth'),
nthPrime = document.querySelector('#nthPrime'),
nthPrimeBtn = document.querySelector('#nthPrimeBtn'),
nthPrimeProgress = document.querySelector('#nthPrimeProgress'),
worker = new Worker('nth-prime-worker.js', {
name: 'nth-prime'
});
randNumBtn.addEventListener('click', onRandNumBtnClick);
nthPrimeBtn.addEventListener('click', onNthPrimeBtnClick);
worker.addEventListener('message', onWorkerMessage);
randNumBtn.click();
/**
* Event listener for random number generate
* @param {Event} e
* @time complexity: O(1)
*/
function onRandNumBtnClick(e) {
e.preventDefault();
randNumTxt.textContent = generateRandomNumber();
}
/**
* Event listener for nthPrimeBtn
* @param {Event} e
* @time complexity: O(1)
* @space complexity: O(1)
*/
function onNthPrimeBtnClick(e) {
e.preventDefault();
const nth = parseInt(randNumTxt.textContent);
worker.postMessage({
action: 'getNthPrime',
nth: nth
});
randNthTxt.textContent = nth;
nthPrimeBtn.setAttribute('disabled', 'disabled');
}
/**
* Event listener for worker
* @param {Event} e
* @time complexity: O(1)
*/
function onWorkerMessage(e) {
switch (e.data.action) {
case 'nthPrime':
nthPrime.textContent = e.data.prime;
nthPrimeBtn.removeAttribute('disabled');
nthPrimeProgress.style.width = '200px';
nthPrimeProgress.textContent = '100%';
break;
case 'nthPrimeProgress':
nthPrime.textContent = e.data.prime;
nthPrimeProgress.style.width = (e.data.progress * 200) + 'px';
nthPrimeProgress.textContent = (e.data.progress * 100).toFixed(2) + '%';
}
}
/**
* Generate a random number from 50000 to 100000
* @return {Number}
* @time complexity: O(1)
*/
function generateRandomNumber() {
return Math.floor(Math.random() * 50000) + 50000;
}
})();