Web workers

Web workers bring the ability to execute code outside the main UI thread. This thread-like behavior allows us to perform long lasting tasks without blocking the user interface. When a JavaScript task takes too long to complete, the browser displays an alert to the user, letting the user know that the page is not responsive. Using web workers, we can solve this problem.

There are a few restrictions with web workers that we need to keep in mind. First, workers run outside the DOM, so any functionality related to that is not available inside worker threads. Also, there is no concept of shared memory with workers—any data that is passed to and from a worker is copied into its own memory space. Finally, any objects passed to and from a worker can contain any data types, except for functions. If you attempt to pass a function to or from a worker (or an object holding a reference to a function), the browser will throw a DataCloneError (DOM Exception 25).

On the other hand, workers are completely capable of firing XHR requests (Ajax calls), starting other workers, and stopping other workers, including themselves. Once a worker is terminated, it can no longer be started, similar to other threading constructs available in other languages such as Java.

How to use it

In this section, we'll create a sample mini application that generates prime numbers in a worker thread. The user can input a number into the application, and the application will return a list of primes up to that number. Those prime numbers will then be passed back to the main application, which will then list the prime numbers back to the user.

To get started with web workers, we must first create a separate JavaScript file that will be run in the worker thread. The way this script will communicate with its parent thread is through messages. In order to receive messages from a parent thread, the worker needs to register a callback function that is called whenever a message is passed to it.

self.addEventListener("message", getPrimes);

The function is called when a message is received, both in the worker thread and in its parent thread, and a MessageEvent object is passed to the function. This object contains many attributes, including a timestamp, and most importantly, a data attribute, which contains any data passed into the worker.

To post a message to a worker or back to its parent, we simply call the function postMessage on the appropriate object (either the worker object, or on the self-object, if inside a worker), passing the data along with the function call. This data can be a single value, an array, or an object of any type, as long as no functions are included.

Finally, to create a worker object, we simply create an instance of the class Worker, passing the path to the worker script as a constructor parameter. This worker object will need to register callback functions for whatever events it wants to observe: onMessage or onError. To kill the worker thread, we can either call the terminate function directly on the worker object, or the close function on the worker script.

// index.html
var worker = new Worker("get-primes.worker.js");

worker.addEventListener("message", function(event){
   var primes = event.data.primes;
   var ul = document.createElement("ul");

   // Parse each prime returned from the worker
   for (var i = 0, len = primes.length; i < len; i++) {
      var li = document.createElement("li");
      li.textContent = primes[i];
      ul.appendChild(li);
   }

   // Clear any existing list items
   var uls = document.querySelectorAll("ul");
   for (var i = 0, len = uls.length; i < len; i++)
      uls[i].remove();

   // Display the results
   document.body.appendChild(ul);
});

var input = document.createElement("input");
input.addEventListener("keyup", function(event){
   var key = event.which;

   // Call the worker when the Enter key is pressed
   if (key == 13 /* Enter */) {
      var input = this.value;

      // Only use input that's a positive number
      if (!isNaN(input) && input > 0) {
         worker.postMessage({max: input});
      } else if (input == -1) {
         worker.terminate();
         this.remove();
      }
   }
});

input.setAttribute("autofocus", true);
document.body.appendChild(input);

In the above snippet, we set up two things: a worker and an input field. We then set up a keydown listener on the input field, which we use so the user can input a number to send to the worker. To send this number to the worker, the user must press the Enter key. When that happens, the number in the input field will be the highest possible prime number generated by the worker. If the user inputs the number -1, the worker is terminated, and the input field is removed from the DOM.

For simplicity, the worker thread will use the Sieve of Eratosthenes to find the primes. Keep in mind that this exercise is only a proof of concept to illustrate how web workers work, and not a lesson on advanced mathematics.

// get-primes.worker.js

// Register the onMessage callback
self.addEventListener("message", getPrimes);

// This function implements the Sieve of Eratosthenes to generate the primes.
// Don't worry about the algorithm so much – focus on the Worker API
function getPrimes(event) {

   var max = event.data.max;
   var primes = [];
   var d = [];

   for (var q = 2; q < max; q++) {
      if (d[q]) {
         for (var i = 0; i < d[q].length; i++) {
            var p = d[q][i];
            if (d[p + q])
               d[p + q].push(p);
            else
               d[p + q] = [p];
         }
         delete d[q];
      } else {
         primes.push(q);
         if (q * q < max)
            d[q * q] = [q];
      }
   }

   // Return the list of primes to the parent thread
   self.postMessage({primes: primes});
}
How to use it

The worker can be invoked an infinite amount of times, as long as it is not terminated. Once terminated, the worker can be deleted, as it serves no useful purpose from that point on.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.204.0