Sunday, December 21, 2008

Two Javascript synchronous sleep functions which won't freeze browser

Javascript didn't provide Thread.sleep(ms) method like Java which is useful for synchronization.

Most of time we can solve Javascript synchronization by use setTimeout or setInteval. However, using setTimeout requires you to split your function up into discrete processes, which is hard to do for some Javascript logic. What we really need is a free-standing function that could be added inline to any block of code to share the processor on the fly.

I encounter a scenario in Selenium today: I want Javascript to sleep to wait for an async call. It's much harder than I thought to implement it. Think about below code:
function sleep(delay) {
   var startTime = new Date();
   var endTime = null;
   do {
       endTime = new Date();
   } while ((endTime - startTime);
} 
It looks fine but if you try it, you will find CPU is very busy executing the while loop and freeze browser. This is not what we wanted.

I got 2 workaround methods. The keypoint is JS NOT freeze CPU/browser during sleep:
1)javascript sleep 1: use XMLHttpRequest to do sync call for sleep.jsp
function wbsleep(ms) { 
  var   startDate = new Date();   
  while((new Date()-startDate) < ms){   
      var xmlHttpReq; 
      try {
         // for IE/ActiveX
         if(window.ActiveXObject) {
             try {
                 xmlHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
             }
             catch(e) {
                 xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
             }
         }
         // Native XMLHttp
         else if(window.XMLHttpRequest) {
             xmlHttpReq = new XMLHttpRequest();
         } 
                tempurl = "http://localhost/sleeputil.jsp?sleepms="+ms;
         xmlHttpReq.open("GET", tempurl, false); // synchron mode  
         xmlHttpReq.send(null);
      }
      catch(e) {  
      } 
  }
};
The sleeputil.jsp is very simple, get request parameter sleepms and then do a Java Thread.sleep(sleepms) in doGet. This method is suitable for all browsers but need you provide a server side sleeputil.jsp.

2)javascript sleep 2: XPCOM on Firefox chrome only
/**
 * Netscape compatible WaitForDelay function.
 * You can use it as an alternative to Thread.Sleep() in any major programming language
 * that support it while JavaScript it self doesn't have any built-in function to do such a thing.
 * parameters:
 *  (Number) delay in millisecond
*/
function nsWaitForDelay(delay) {
  try{
    /**
    * Just uncomment this code if you're building an extention for Firefox.
    * Since FF3, we'll have to ask for user permission to execute XPCOM objects.
    */
    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");

    // Get the current thread.
    var thread = Components.classes["@mozilla.org/thread-manager;1"].getService(Components.interfaces.nsIThreadManager).currentThread;

    // Create an inner property to be used later as a notifier.
    this.delayed = true;

    /* Call JavaScript setTimeout function
     * to execute this.delayed = false
     * after it finish.
     */
    setTimeout("this.delayed = false;", delay);

    /**
     * Keep looping until this.delayed = false
    */
    while (this.delayed) {
        /**
         * This code will not freeze your browser as it's documented in here:
         * https://developer.mozilla.org/en/Code_snippets/Threads#Waiting_for_a_background_task_to_complete
        */
        thread.processNextEvent(true);
    }
  }catch(e) {  
  } 
}
This is especially suitable for Selenium CORE*ffchrome.

1 comment:

  1. JavaScript is a good program and very easy to use. I don´t like a complex program. I prefer javascript because i consider it like a device very eficient and it have a good quality.
    I always looking for the quality that is why i prefer to buy viagra because i always have a great result in my sexual life.

    ReplyDelete