MaiDeveloper

Introduction to Web Worker API

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.

Introduction to Web Worker API Demo

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;
  }

})();


Mike Mai
Mike Mai   Brooklyn, New York
I am full-stack web developer, passionate about building world class web applications. Knowledge in designing, coding, testing, and debugging. I love to solve problems.