HTML 5 Web Workers

Web Worker

 
A web worker is a JavaScript running in the background, without affecting the performance of the page. They are generally external script files that run in the background. It is supported by the majority of browsers:
 
 

Advantages

 
We know web browsers increased a lot over the past few years and it is primarily because of lot of work done on its engines, ex- V8 (Google), Chakra (Microsoft). The JavaScript so far runs in a single thread. The problem with single-threaded architecture is that it blocks the code and UI becomes unresponsive in case of running the complex script. There are various ways to solve this problem:
  • Offload work to the server, but to make apps faster fat client is preferred
  • Use asynchronous calls, but many complex ecosystem of async calls & promises could lead into callback hell
  • Leverage multi-threading. Interesting!
Web Workers solve this issue by providing the capability of multi-threading in JavaScript.  
 
Let's define a problem first and solve for that.
 

Problem statement

 
If you run a heavy JavaScript script then the UI becomes unresponsive and throws the following error. This is a very common problem “Unresponsive script” that we all have seen someday or the other. 
 
Unresponsive script error
 
I've written a sample code with a problem and the solution also.
 
Index.html
  1. <!DOCTYPE html>    
  2. <html>    
  3. <head>    
  4.     <title>Unresponsive dialog problem</title>    
  5. </head>    
  6. <body>    
  7. <input id="num">    
  8. <button id="btnWordsSol">Get Words - Solution</button>    
  9. <button id="btnWordsPrb">Get Words - Problem</button>    
  10. <button id="btnTerminate">Terminate</button>    
  11. <button id="btnClear">Clear</button><br><br>    
  12. <div id="msg"></div>    
  13. <script type="text/javascript" src="js/vendor/jquery-1.10.2.min.js"></script>    
  14. <script type="text/javascript">    
  15.     var worker=new Worker('js/solutions.js');    
  16.     $('#btnClear').click(function() {    
  17.         $('#msg').text('');    
  18.     });    
  19.     
  20.     $('#btnTerminate').click(function() {    
  21.         $('#msg').text('');    
  22.         if(worker)    
  23.         {    
  24.             worker.terminate();    
  25.             worker=null;    
  26.             $('#msg').text('worker destroyed');    
  27.             $('#prg').val(0)        ;    
  28.         }    
  29.     });    
  30.     $('#btnWordsSol').click(function() {    
  31.         $('#msg').text('');    
  32.     
  33.         var num=$('#num').val();    
  34.         if(worker == null)    
  35.             worker=new Worker('solution.js');    
  36.         worker.postMessage(num);    
  37.         worker.onmessage=function(event) {    
  38.             if(event.data.percent!=null)    
  39.                 $('#prg').val(event.data.percent)    
  40.             $('#msg').text(event.data.showText);    
  41.         }    
  42.     
  43.         worker.onerror=function(event) {    
  44.             $('#msg').text(event.lineno+ ' : '+ event.message);    
  45.         }    
  46.     });    
  47.     
  48.     $('#btnWordsPrb').click(function() {    
  49.         $('#msg').text('');    
  50.     
  51.         var text1="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore t dolore magna aliqua. Ut enim ad minim veniam,quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodoconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat nonproident, sunt in culpa qui officia deserunt mollit anim id est laborum.";    
  52.         var arrOfWords=text1.split (" ");    
  53.         // console.log('length of our para: '+arrOfWords.length)    ;    
  54.         var tempStr="";    
  55.         var index;    
  56.         var num=$('#num').val();    
  57.         for (var i = 1; i <= num; i++) {    
  58.             index= Math.floor(Math.random()*arrOfWords.length);    
  59.             tempStr+=" "+arrOfWords[index];    
  60.         }    
  61.         $('#msg').text(tempStr);    
  62.     
  63.     });    
  64. </script>    
  65.     
  66. </body>    
  67. </html>   
     
Download this code and run this in the webserver, for example, http://localhost/webworker/index.html
 
It looks like this:
 
Unresponsive dilog problem1
 
Enter any number, say 100 in the text box and click “Get Words – Problem” and see the output of random words, for example:
 
Unresponsive dilog problem2
 
This button will work if you want to generate the number of words in the text box, say 1000000 (it may be less at your machine). But if you enter a higher value, say 10000000, then after clicking “Get Words – Problem” it'll throw the following message after some time:
 
warning Unresponsive script
 
Solution
 
To solve these problems, let's leverage the WW provided by HTML5. Enter the same number in the text box 10000000 and click “Get Words – Solution” and it'll work. We'll review the Web Worker life cycle, i.e.,
  • spawning a worker (installing, activate)
  • idle
  • post message
  • terminate
  • error
     
 
Spawning a worker
 
To create a Web Worker is simple and you need a new JavaScript file that contains code that you want WebWorker to execute. Hence, the below code will create a new object from Worker.
  1. $('#btnWordsSol').click(function()    
  2.     
  3. var worker=new Worker('solution.js');   
Communicating with a Web Worker
 
To use these Web Workers in the real world you need to establish a communication. These messages could be a simple string, objects. The preceding line will load the script located at “worker.js” and execute it in the background. You need to call the Worker() constructor with the URI of a script to execute in the Worker thread as in the following:
  1. worker.postMessage(num);    
  2.     
  3.  worker.onmessage=function(event) {    
  4.    if(event.data.percent!=null)    
  5.     $('#prg').val(event.data.percent)    
  6.    $('#msg').text(event.data.showText);    
  7.   }   
If you want to get data from the Worker (for example, the output of the processed information, notifications, and so on) then you should set the Worker's onmessage property to an appropriate event handler function. The onmessage event is callback that receives the value from the background JavaScript. It also sends data back via postMessage.
 
Capturing error
 
Web Workers support onerror event. The onerror event captures a JavaScript error that occurs in the background JavaScript.
  1. worker.onerror=function(event) {    
  2.   $('#msg').text(event.lineno+ ' : '+ event.message);    
  3.  }   
If you want to terminate WW in between then you can click the Terminate button that will kill between the worker processes as in the following:
 
worker.terminate();
 
terminate WW
 
You can use self or this keyword to access onmessage. It's sending data back to problem.html via self.postMessage.
 
So, communication between the foreground thread running problem.html and the background thread running solution.js is done via postMessage.
 

Theory of WW

 
WW runs JavaScript via background thread. Don't be surprised, JavaScript now has background thread execution capability. We know JavaScript is single-threaded and scripts execute sequentially.
 
But, it's a real thread, spawned by the OS, that executes in the background.
 

Features available to WW

 
Due to the multi-threaded behavior, a WW only has access to the following subset of JavaScript features:
  • the navigator object
  • the location object
  • XMLHttpRequest
  • setTimeOut/clearTimeOut/setInterval/clearInterval
  • importScripts
  • spawning other WW

Limitations of WW

 
It has some limitations apart from its multithreading advantage, i.e., it can't access:
  • DOM elements
  • window object
  • document object
  • parent object

Types of WW

 
Primarily there are three dedicated, shared, and inline workers. What we've seen above is an example of dedicated. I'll post another blog for shared and inline in detail and some more interesting features. Keep watching this space.
 
Please share the feedback.