<!DOCTYPE HTML>
<html>
 <head>
  <title>A worker in action</title>
  <script>
    var totalMsDiff = [0]; // Keep track of delay with webworker's interval callback
    var inactiveTabStart = 0;
  
    // Helper
    function addText(str) {
      if (false) { // Append
        document.body.innerHTML += '<br/>' + str;
      } else { // Prepend
        document.body.innerHTML = '<br/>' + str + document.body.innerHTML;
      }
    }
  
    // Worker
    var worker = new Worker('worker.js');
    // Notified from worker
    worker.onmessage = function (event) {
      var now = new Date();
      
      var workerTime = event.data;
      var windowTime = now.toString().split(' ')[4];
      var msDiff = now.getTime() - workerTime.ms;
      totalMsDiff.push(msDiff);
      
      var text = [
        'Worker time: ',
        workerTime.str,
        ', Difference:',
        msDiff,
        'milliseconds'
      ].join(' ');
      addText(text);
    };
    
    // Window blur/focus checks for demonstration purposes
    window.onblur = function() {
      addText('Window BLUR');
    };
    window.onfocus = function() {
      addText('Window FOCUS');
    };
      
    // Page Visibility API for demonstration purposes
    // Taken from https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API#Example
    // Set the name of the hidden property and the change event for visibility
    var hidden, visibilityChange; 
    if (typeof document.hidden !== "undefined") {
      hidden = "hidden";
      visibilityChange = "visibilitychange";
    } else if (typeof document.mozHidden !== "undefined") {
      hidden = "mozHidden";
      visibilityChange = "mozvisibilitychange";
    } else if (typeof document.msHidden !== "undefined") {
      hidden = "msHidden";
      visibilityChange = "msvisibilitychange";
    } else if (typeof document.webkitHidden !== "undefined") {
      hidden = "webkitHidden";
      visibilityChange = "webkitvisibilitychange";
    }
      
    // Handler
    function handleVisibilityChange() {
      if (document[hidden]) {
        // start keeping data
        msDiff = [0];
        inactiveTabStart = new Date();
      } else {
        // show summary
        var pop = totalMsDiff.length;
        var diff = totalMsDiff.reduce(function(prev, curr){ return prev + curr; }) / pop;
        addText('<b>Theoritically slower by ' + Number(diff/200).toFixed(5) + '% (with 200ms per interval)</b>');
        addText('<b>Delay per call: ' + Number(diff).toFixed(5)  + ' milliseconds</b>');
        addText('<b>Tab inactivity: ' + Number(((new Date()).getTime() - inactiveTabStart.getTime()) / (60 * 1000)).toFixed(1) + ' minutes</b>');
        addText('================');
      }
      addText('Visibility ' + (document[hidden]?'HIDDEN':'VISIBLE'));
    }
    document.addEventListener(visibilityChange, handleVisibilityChange, false);
  </script>
 </head>
 <body>

 </body>
</html>
(function(){
  
  function heartbeat() {
    var time = new Date();
    var timeStr = time.toString().split(' ')[4];
    self.postMessage({ str: timeStr, ms: time.getTime() });
  }

  setInterval(function(){
    heartbeat();
  }, 200);

})();