XMLHttpRequest Leak in IE 7/8, forgot the abort thing!

After I was done writing my previous post XMLHttpRequest Leak in IE 7/8 I suddenly remembered that I had missed the ‘abort’ method of ‘XMLHttpRequest’.

It means what it says:-) It aborts the current call.

Many a times I want to do some housekeeping either before or after calling the ‘abort’ method. To make the housekeeping transparent I will usually end up over-riding ‘abort’ before exposing it. Many libraries do it including jQuery. Consider the following code:

<html>
<head>
	<title>xmlHttpRequest Leak, Abort Override Demo</title>
<script>

function makeAjaxCall(){
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'test1.php', true);
    xhr.onreadystatechange = function (event){
      if(xhr.readyState == 4 && xhr.status == 200){
         //clean up to avoid leaks
         xhr.onreadystatechange = new Function;
         xhr = null;
      }
   };
   
   //override abort here
   var oldAbort = xhr.abort;
   xhr.abort = function() {
   	if ( xhr ) {
   		oldAbort.call( xhr );
   	}
      //some housekeeping code
      //-----
      //-----
   	
   };
	
   xhr.send(null);
   return xhr;
} 


var xhr = makeAjaxCall();

//To abort I would call
xhr.abort();
  
</script>
  
</head>

<body>
</body>
</html>

Note that I have over-ridden the abort method. Nothing fancy or tricky here.

Just to make sure everything is OK I am going to create a test to check for any leaks. Here is the test case you are probably familiar with by now:

leak-test4.html

<html>
<head>
	<title>xmlHttpRequest Leak, Abort Override Demo</title>

<script>

var interval;
var i = 1000;
function fire(){
  interval = setInterval(makeLeak, 50); 
} 

function makeLeak(){
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'test1.php?i='+i, true);
    xhr.onreadystatechange = function (event){
      if(xhr.readyState == 4 && xhr.status == 200){
         //cleanup to avoid leaks
         xhr.onreadystatechange = new Function;
         xhr = null;
            if(--i === 0){
               clearInterval(interval);
               interval = null;
               alert('All Done');
            }
      }
   };
   
   
   var oldAbort = xhr.abort;
   xhr.abort = function() {
   	if ( xhr ) {
   		oldAbort.call( xhr );
   	}
      //housekeeping code
      //----
      //------
   	
   };
	
   xhr.send(null);
   
   return xhr;
} 


  
</script>
  
</head>


<body>
   <button id = "button1" onclick="fire(false);">Fire</button>
</body>
</html>

Running this in sIEve produces the following:

IE Leak Abort
IE Leak Over-riding Abort

It seems there is a leak. I confirmed that I had cleaned up by putting the following code in the ‘xhr.onreadystatechange’ callback handler. What went wrong now?

xhr.onreadystatechange = new Function;
xhr = null;

Well I did not do a thorough job of cleaning up!. It seems I forgot to use my own advice. Like I mentioned in my previous post, you need to clean up functions you over-ride. I need to clean up ‘abort’ by adding the following:
xhr.abort= new Function;

My ‘xhr.onreadystatechange’ handler will now look like this:

xhr.onreadystatechange = function (event){
      if(xhr.readyState == 4 && xhr.status == 200){
         //cleanup to avoid leaks
         xhr.onreadystatechange = new Function;
         xhr.abort = new Function; //clean up abort override
         xhr = null;
            if(--i === 0){
               clearInterval(interval);
               interval = null;
               alert('All Done');
            }
      }
   };

Having done that, this is what I get from sIEve

IE Leak Abort Fig 2
IE Leak Over-riding Abort Fig 2

Notice that the leak has stopped.

Remember, always cleanup after yourself.

Happy computing!

Advertisements

XMLHttpRequest Leak in IE 7/8

Recently I came across a leak in a legacy IE 7/8 application. Memory was building up proportionally with the increasing frequency of AJAX calls. Further research brought me to this page Internet Explorer: memory leak in XMLHttpRequest (on-page) where to my surprise I found the reason for the leaks.

Sergey Ilinsky, the author of the page notes:

“Bug: The instance of XMLHttpRequest doesn’t get garbage collected in case you have a reference to the instance or to an other COM object (for example: DOM Node etc.) in its onreadystatechange handler, thus producing runtime memory leaks. “

He has also proposed a fix. I will talk about that in a moment.

To measure the leak here is a simple test page, test-leak1.html.

test-leak1.html

<html>
<head>
	<title>xmlHttpRequest Leak Demo I</title>

<script>

var interval;
var i = 1000;
function fire(){
  interval = setInterval(makeLeak, 50);
} 

function makeLeak(){
    var xhr = new XMLHttpRequest();
    //open ajax call. 'i' is dummy character to avoid caching of requests
    xhr.open('GET', 'test1.php?i='+i, true);
    xhr.onreadystatechange = function (event){
      if(xhr.readyState == 4 && xhr.status == 200){
            //all iterations done...stop timer and cleanup
            if(--i === 0){
               clearInterval(interval);
               interval = null;
               alert('All Done');
            }
      }
   };
   xhr.send(null);

}
</script>
</head>

<body>
   <button id = "button1" onclick="fire();">Fire</button>
</body>
</html>

The setup is extremely simple where after the ‘Fire’ button is clicked 1000 AJAX calls are made at 50ms intervals.

The test1.php contains on an echo statement. The intent being that I don’t want to do any data processing.

<?php
echo '';
?>

Here are the results when you run ‘test-leak1.html’ in ‘sIEve’:

IE Leak Test Fig 1
IE Leak Test Fig 1

Note that memory consumption grows from 13748 bytes to 31764 bytes. More than doubled and we haven’t even processed any data or manipulated DOM elements. You can very well imagine the damage this can do in an intensive AJAX application.

So, what is causing the leak? Let’s dissect the code to understand:

  1. 1. ‘makeLeak’ function is called.
  2. 2. An instance of ‘XMLHttpRequest’ is created and its reference put in the variable ‘xhr’.
  3. 3. The ‘open’ method is called to prepare the send request. Note the request is not sent yet.
  4. 4. ‘xhr.onreadystatechange’ callback is defined
  5. 5. The request is now sent using the ‘send’ method.
  6. 6. ‘makeLeak’ function ends and goes out of scope.

Form the above we can draw the following logical observations:

  1. 1. ‘makeLeak’ is the outer function.
  2. 2. ‘xhr.onreadystatechange’ is the inner function.
  3. 3. The inner function(‘xhr.onreadystatechange’) has access to the ‘xhr’ variable defined in its outer scope. This is true even though the outer function has gone out of scope! Think of ‘xhr’ as a static variable.
  4. 4. This implies that the outer function(‘makeLeak’) closes over the inner function ‘xhr.onreadystatechange’. Hence ‘makeLeak’ is a ‘closure’.

When the AJAX call returns:

  1. 1. ‘xhr.onreadystatechange’ fires.
  2. 2. A check is made if the AJAX call is successful(xhr.readyState == 4 && xhr.status == 200).
  3. 3. If it is not done it returns. Note that the outer variable ‘xhr’ still holds a valid reference to the ‘XMLHttpRequest’ object.
  4. 4. If it is successful(xhr.readyState == 4 && xhr.status == 200) then as far as IE is concerned the AJAX call is done.
  5. 5. When the garbage collector comes around it finds the inner function still referencing ‘xhr’ in the outer function’s scope. It leaves it alone.
  6. 6. So every time ‘makeLeak’ is called, a new instance of XMLHttpRequest is created and orphaned.

But before we start fixing this leak let’s confirm that XMLHttpRequest is still alive in well even after everything is over. Consider the following code:

test-leak3.html

<html>
<head>
<title>xmlHttpRequest Leak Demo I</title>

<script>
var success = false;

function makeLeak(){
   console.log('In outer function scope');
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'test2.php', true);
    xhr.onreadystatechange = function (event){
      if(xhr.readyState == 4 && xhr.status == 200){
         console.log('In inner function scope(AJAX Success). Response text: ' + xhr.responseText);
         success = true;
      }
   };
   xhr.send(null);

   //return reference to xhr
   var getXhr = function(){
      return xhr;
   }
   //return the reference to the function getXhr
   return getXhr;
}   

//call function makeLeak. starts the AJAX process and returns a reference
//to the method getXhr. In other words g() = makeLeak.getXhr()
var g = makeLeak();

//set up a timer to check the state of 'xhr' after the AJAX call completes.
var interval = setInterval(checkXhr, 1000);

function checkXhr(){
   if(success === true){
      //get the value of xhr;
      var xhr = g();
      if(xhr){
         console.log('xhr.responseText: ' + xhr.responseText);
      }else{
         console.log('xhr.responseText: ' + xhr);
      }
      //cleanup
      clearInterval(interval);
      interval = null;
   }
}
</script>
</head>

<body>
</body>
</html>

and test2.php contains:

<?php
echo 'Hello';
?>

The intent is to check the state of the ‘XMLHttpRequest’ object after the AJAX call is complete.

The ‘makeLeak’ function defines two inner functions. One is the callback ‘xhr.onreadystatechange’ and the other is ‘getXhr’. ‘getXhr’ only returns the handle to the ‘XMLHttpRequest’ object.

I have also defined a new variable ‘success’ . Once the AJAX call is successful it is set to ‘true’. The interval handler checks for the ‘success’ flag and if true tries to get the handle to the XMLHttpRequest object(xhr in makeLeaK). Once it has that it displays ‘responseText’.

Let’s check it out. After running the file the console windows shows the following:
Console [20]=
In outer function scope

Console [21]=
In inner function scope(AJAX Success). Response text: Hello

Console [22]=
xhr.responseText: Hello

Notice that even though ‘makeLeak’ has gone out of scope its internals are preserved. The bottom line is that the garbage collector will not cleanup an object if it determines that there is a reference to the object. So we need to help out. Please consider the following code in test-leak2.html.

test-leak2.html

<html>
<head>
	<title>xmlHttpRequest Leak Demo I</title>

<script>

var interval;
var i = 1000;
function fire(){
  interval = setInterval(makeLeak, 50);
} 

function makeLeak(){
    var xhr = new XMLHttpRequest();
    //open ajax call. 'i' is dummy character to avoid caching of requests
    xhr.open('GET', 'test1.php?i='+i, true);
    xhr.onreadystatechange = function (event){
      if(xhr.readyState == 4 && xhr.status == 200){
            //make object null, help the garbage collector to clean up
            xhr.onreadystatechange = new Function; //empty function
            xhr = null;
            //all iterations done...stop timer and cleanup
            if(--i === 0){
               clearInterval(interval);
               interval = null;
               alert('All Done');
            }
      }
   };
   xhr.send(null);

}
</script>
</head>

<body>
   <button id = "button1" onclick="fire();">Fire</button>
</body>
</html>

The only difference between this file and ‘test-leak1.html’ is these two lines in the ‘xhr.onreadystatechange’ handler:

xhr.onreadystatechange = new Function; //empty function
xhr = null;

Only xhr = null would also work but it is always a good practice to cleanup all that you have defined. In this case we defined the callback so replace it with an empty function.

Now if I run test-leak2.html in sIEve here is what I get:

IE Leak Fig 2
IE Leak Fig 2

There is virtually no memory buildup and it seems to have stabilized around 15,400 bytes.

I hope reading this post was as educational for you as it was for me writing it.

Happy computing!

jQuery Document Ready…the sequel

My previous post jQuery Document Ready, the saga continues… got me thinking. Why not write a jQuery plugin which simulates a ready handler tied to an AJAX success handler. Let me explain.

Consider test1.html, view1.html and test1.js from the previous post:
test1.html

<html>
    <head>
        <title>Document Ready Demo</title>

        <script src = "jquery-1.4.2.js"></script>
        <script src = "test1.js"></script>

        <script>
            $(document).ready(function () {
                //make sure there is no caching to avoid confusion
                $.ajaxSetup({cache: false});

                $('#fetchView1').click(function () {
                    $.get('view1.html', function (data) {
                        $('#viewText1').html(data);
                    });
                });
            });
        </script>
    </head>

    <body>
        <button id = "fetchView1">Fetch View1</button>

        <div id = "viewText1">
            View1 content goes here
        </div>
    </body>
</html>

view1.html

<div>
   <input type="text" id="inputView1" value="Click button to fill with 1111" size="50" />
   <button id="buttonView1">Fill Input with number 1111</button>
</div>

test1.js

(function($) {
   $(document).ready(function(event) {

   console.log('test1.js document.ready executed');

   $('#buttonView1').click(function() {
        console.log('buttonView1 view clicked');
        $('#inputView1').val('1111');
   });
   console.log('buttonView1 button bound now');

//possibily more processing code and bindings

   });
})(jQuery);

Like I discussed, the intent of having the document.ready is that somehow it attaches itself to view1.html. Well it attaches itself to test1.html and because of this programmers resort to using live or liverquery. Again, nothing wrong with these tools but the penalty of freedom is performance overhead.

Ideally it would be nice if we could execute the JS code on AJAX success, rather automatically. Taking a cue and inspiration from the livequery plugin this is what I came up with:

jquery.jready.js

/*!
 * jQuery plugin jReady v1.0
 * https://phptouch.com/
 *
 * Copyright 2011, Jayesh Wadhwani
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * Released under the MIT, BSD, and GPL Licenses.
 *
 * Date: 31-July-2011
 */
(function($) {
    $.fn.jready = function(jreadyId, fn) {
        var j;
        //make a jready object
        j = new $.jready(this, jreadyId, fn);
        return this;
    };
    
    //jready function. Objects are made of this
    $.jready = function(context, jreadyId, fn) {
//        this.selector = selector;
        this.jreadyId = jreadyId;
        this.context = context || document;
        this.fn = fn;
        this.id = $.jready.fns.push(this) - 1;

        return this;
    };
    
    //function prototype
    $.jready.prototype = {
        //execute attached functions
        execute: function() { 
         var that = this; 
         this.context.each(function(){
            that.fn.apply(this);   
         })
         
        }
    };

    $.extend($.jready, {
        fns: [], //jready objects collection
        //jready handler
        execute: function(event, xhr, settings) {
            //check if there is a jready id present in the url
            var match = /.+?jready=(\w+)[\?\&]?/ig.exec(settings.url);

            if (match !== null) {
                var jreadyId = match[1] || null;
                //if there is a jready toke/id present then 
                //check if in the collection and execute the handler
                //in the object
                if (jreadyId) {
                    $.each($.jready.fns, function(index, fn) {
                        if (fn.jreadyId == jreadyId) {
                            fn.execute();
                            return false;
                        };
                    });
                }
            }
        },
        //bind the global ajax success
        bind: function() { $(document).ajaxSuccess($.jready.execute); }
    });
    // //bind the global ajax success when dom is ready
    $(function() { $.jready.bind(); });
})(jQuery);

I will explain the internals of the plugin in a minute.

Using this plugin test1.js now contains:

(function($) {
   $(document).jready('view1', function(event) {
      console.log('test1.js-view1 jready executed');    
      
      $('#buttonView1').click(function(){
         console.log('buttonView1 view clicked');
         $('#inputView1').val('1111');
      });
      console.log('buttonView1 button bound now');
      //event bidings
      
      //processing code
      
   });
})(jQuery);

Finally test1.html now contains:

<html>
    <head>
        <title>Document Ready Demo</title>

        <script src = "jquery-1.4.2.js"></script>
        <script src = "jquery.jready.js"></script>
        <script src = "test1.js"></script>

        <script>
            $(document).ready(function () {
                //make sure there is no caching to avoid confusion
                $.ajaxSetup({cache: false});

                $('#fetchView1').click(function () {
                    $.get('view1.html?jready=view1', function (data) {
                        $('#viewText1').html(data);
                    });
                });
            });
        </script>
    </head>

    <body>
        <button id = "fetchView1">Fetch View1</button>

        <div id = "viewText1">
            View1 content goes here
        </div>
    </body>
</html>

If I now run test1.html, no binding takes place. It only takes place when the AJAX call completes. Let me explain how that happens.

1. In the URL I have attached an identifying token, ‘view1.html?jready=view1. This token can be any alpha-numeric characters.

2. In test1.js I have replaced $(document).ready(function(event) with $(document).jready(‘view1’, function(event) . Note that the “event type” here is identical to the identifying token in the URL

3. When $(document).jready(‘view1’, function(event) is executed, all the plugin does is to store away the handler function in a function object which in turn is stored in an array.

4. Also note that the global handler ajaxSuccess at the end of the plugin code. The function attached to this event checks for a valid identifying token. If a valid token is detected then it iterates over all function objects looking for a match. If a match is found then it executes the jready handler.

I still have to work on the plugin, particularly in the area of error handling. But for now it should be enough to get you going.

Elementary I believe:-)

Happy Computing!

jQuery Document Ready, the saga continues…

Further to my earlier post jQuery Document Ready…use it wisely! one reader pointed out a different kind of architecture:

The html, test1.html:

<html>
    <head>
        <title>Document Ready Demo</title>

        <script src = "jquery-1.4.2.js"></script>
        <script src = "test1.js"></script>

        <script>
            $(document).ready(function () {
                //make sure there is no caching to avoid confusion
                $.ajaxSetup({cache: false});
                
                $('#fetchView1').click(function () {
                    $.get('view1.html', function (data) {
                        $('#viewText1').html(data);
                    });
                });
            });
        </script>
    </head>

    <body>
        <button id = "fetchView1">Fetch View1</button>

        <div id = "viewText1">
            View1 content goes here
        </div>
    </body>
</html>

When the button is clicked, an AJAX call is made. This call fetches the contents of view1.html and puts it in the div with id viewText1. Now let’s look at the view:

view1.html:

<div>
   <input type="text" id="inputView1" value="Click button to fill with 1111" size="50" />
   <button id="buttonView1">Fill Input with number 1111</button>
</div>


A very simple view file indeed. Just an input text field and a button. The objective being that when this button is clicked the event handler will fill the input field with '1111'. So where is the event binding and handler? That is in the included test1.js.

The included test1.js looks like this:

(function($) { 
   $(document).ready(function(event) {

   console.log('test1.js document.ready executed');

   $('#buttonView1').click(function() {
        console.log('buttonView1 view clicked');
        $('#inputView1').val('1111');
   });
   console.log('buttonView1 button bound now');

//possibily more processing code and bindings

   });
    
})(jQuery);

Note here that the button is attached to the click event handler which fills the input with '1111'. There is also a document.ready binding and its handler which will fire when the document is good and ready. The question is which document. The answer in a minute:-)

When I run test.html1 in a browser the console displays the following:

Console [1]= test1.js document.ready executed

Console [2]= buttonView1 button bound now

Now if I were to click on the button titled "Fetch View1" the AJAX call fires and the browser output should look something like this:

If you now click the button you probably expect to see the input box filled with '1111'. But when you do, nothing happens. However the console statement above does indicate that the button was bound!

The problem is that the binding in test1.js took place when the document.ready fired which was when test1.html was loaded. At this time view1 did not exist and obviously neither did the input field and the button. So the binding in test1.js was ineffective and of no use. Imagine 55 JS included files with an average of 5 binding in each and each file with a document.ready handler. Every handler firing when the outer document is loaded. Waste of resources!

The binding should actually take place after view1.html is loaded. Not fully understanding this concept programmers resort to using live event binding or the livequery plugin. Mind you, both these are superb tools but if used without proper understanding your application will suffer from severe performance issues.

Two simple solutions come to mind.

1. Put the JS code in view1.html wrapped in document ready.

<script>
 $(document).ready(function(event) {

   console.log('test1.js document.ready executed');

   $('#buttonView1').click(function() {
        console.log('buttonView1 view clicked');
        $('#inputView1').val('1111');
   });
   console.log('buttonView1 button bound now');


//possibily more processing code and bindings

   });
</script>
<div>
   <input type="text" id="inputView1" value="Click button to fill with 1111" size="50" />
   <button id="buttonView1">Fill Input with number 1111</button>
</div>

Remove the test1.js include from test1.html:

<html>
    <head>
        <title>Document Ready Demo</title>

        <script src = "jquery-1.4.2.js"></script>

        <script>
            $(document).ready(function () {
                //make sure there is no caching to avoid confusion
                $.ajaxSetup({cache: false});

                $('#fetchView1').click(function () {
                    $.get('view1.html', function (data) {
                        $('#viewText1').html(data);
                    });
                });
            });
        </script>
    </head>

    <body>
        <button id = "fetchView1">Fetch View1</button>

        <div id = "viewText1">
            View1 content goes here
        </div>
    </body>
</html>

If you run this, you will see that the bindings work fine and the input field is filled with '1111' when the button is clicked. Reason being that jQuery considers view1.html as a document and fires the document.ready event when the view1.html DOM has loaded. Remember this will only work if you are using jQuery methods such as html, append etc. It will not work if you use core dom methods/properties such as innerHTML.

2. Make test1.js a function call.

You could also change test1.js as a function and call it after the AJAX call completes like so:

test1.js will now contain:

function test1(){ 
   console.log('test1.js function executed');

   $('#buttonView1').click(function() {
        console.log('buttonView1 view clicked');
        $('#inputView1').val('1111');
   });
   console.log('buttonView1 button bound now');

//possibily more processing code and bindings
}

test1.html will now become:

<html>
    <head>
        <title>Document Ready Demo</title>

        <script src = "jquery-1.4.2.js"></script>
        <script src = "test1.js"></script>

        <script>
            $(document).ready(function () {
               $.ajaxSetup({cache: false});
               
                $('#fetchView1').click(function () {
                    $.get('view1.html', function (data) {
                        $('#viewText1').html(data);
                        test1();
                    });
                });
            });
        </script>
    </head>

    <body>
        <button id = "fetchView1">Fetch View1</button>

        <div id = "viewText1">
            View1 content goes here
        </div>
    </body>
</html>

and finally view1.html will go back to its original form:

<div>
   <input type="text" id="inputView1" value="Click button to fill with 1111" size="50" />
   <button id="buttonView1">Fill Input with number 1111</button>
</div>

If you now run test1.html it will work as expected. Note the function call test1.js() after the AJAX call completes.

This is only the beginning. I am sure you have thought of other ways of doing this. My main purpose however of writing this post is to emphasize not to use document.ready, live bindings or livequery before fully understanding as to what is involved. For everything there is a purpose and a matching tool. Be prudent and pragmatic.

Happy programming!

Regular Expressions, the Faster, Simpler Alternative

Sometime back I came across the following snippet:

function containsBadChars(str){
      if ((str.indexOf("\#") != -1) ||
          (str.indexOf("\&") != -1) ||
          (str.indexOf("\=") != -1) ||
          (str.indexOf("\\") != -1) ||
          (str.indexOf("\?") != -1) ||
          (str.indexOf("\:") != -1) ||
          (str.indexOf("\;") != -1) ||
          (str.indexOf("\'") != -1) ||
          (str.indexOf("\"") != -1) ||
          (str.indexOf("\[") != -1) ||
          (str.indexOf("\]") != -1) ||
          (str.indexOf("\{") != -1) ||
          (str.indexOf("\}") != -1)){
              return true;
          } else{
              return false;
          }
       };

This functions checks the existence of any of the following characters ‘#’, ‘&’, ‘=’, ‘\\’, ‘?’, ‘:’, ‘;’, ‘\”, ‘”‘, ‘[‘, ‘]’, ‘{‘, ‘}’ and returns true if found.

Using Regular Expressions we can modify this function in a more elegant one like this:

function containsBadCharsRegex(str){
      return /[\#\&\=\\\?\:\;\'\"\[\]\{\}]/.test(str);
};

Every time I talk about elegance with programmers they point out the performance gain/loss issue. A valid concern. So I did a performance test. Here is the code I used:

<html>
<head>
<title>Regex Demo</title>
<head>
   
<script>
    //in-elegant but functionally operational function
    function containsBadChars(str){
      if ((str.indexOf("\#") != -1) || 
          (str.indexOf("\&") != -1) || 
          (str.indexOf("\=") != -1) || 
          (str.indexOf("\\") != -1) ||
          (str.indexOf("\?") != -1) || 
          (str.indexOf("\:") != -1) || 
          (str.indexOf("\;") != -1) || 
          (str.indexOf("\'") != -1) || 
          (str.indexOf("\"") != -1) || 
          (str.indexOf("\[") != -1) || 
          (str.indexOf("\]") != -1) || 
          (str.indexOf("\{") != -1) || 
          (str.indexOf("\}") != -1)){
              return true; 
          } else{ 
              return false;
          }
       };
       
    //elegant and functionally operational function   
    function containsBadCharsRegex(str){
      return /[\#\&\=\\\?\:\;\'\"\[\]\{\}]/.test(str);
    };
    
    //List of test characters
    //Last four are valid characters
    //first 13 bad characters
    var testCharacters = ['#', '&', '=', '\\', '?', ':', ';', '\'', '"', '[', ']', '{', '}', '$', 'H', '1', '*']; 
   
    console.log('Testing the long way:');
    console.profile() 
    //check each character
    for(var i in testCharacters){
      //create the test string
      var str = "The quick brown fox quickly jumped over the lazy dog. This is the " + testCharacters[i] + " for testing";
      var isValid = containsBadChars(str);
      //comment for profiling
      console.log('Long Way. Character: ' + testCharacters[i] + ' isValid: ' + isValid);
    }
    console.profileEnd()
    
    console.log('Testing the short(regex) way');
    console.profile() 
    for(var i in testCharacters){
      var str = "The quick brown fox quickly jumped over the lazy dog. This is the " + testCharacters[i] + " for testing";
      var isValid = containsBadCharsRegex(str);
      //comment for profiling
      console.log('Short(Regex) Way. Character: ' + testCharacters[i] + ' isValid: ' + isValid);
    }
    console.profileEnd()
    
</script>
</head>
<body>
</body>
</html>

First we need to make sure that they are functionally identical.

Running the program gives the following console log output:

Testing the long way:
Long Way. Character: # isValid: true
Long Way. Character: & isValid: true
Long Way. Character: = isValid: true
Long Way. Character: \ isValid: true
Long Way. Character: ? isValid: true
Long Way. Character: : isValid: true
Long Way. Character: ; isValid: true
Long Way. Character: ‘ isValid: true
Long Way. Character: ” isValid: true
Long Way. Character: [ isValid: true
Long Way. Character: ] isValid: true
Long Way. Character: { isValid: true
Long Way. Character: } isValid: true
Long Way. Character: $ isValid: false
Long Way. Character: H isValid: false
Long Way. Character: 1 isValid: false
Long Way. Character: * isValid: false

Testing the short(regex) way:
Short(Regex) Way. Character: # isValid: true
Short(Regex) Way. Character: & isValid: true
Short(Regex) Way. Character: = isValid: true
Short(Regex) Way. Character: \ isValid: true
Short(Regex) Way. Character: ? isValid: true
Short(Regex) Way. Character: : isValid: true
Short(Regex) Way. Character: ; isValid: true
Short(Regex) Way. Character: ‘ isValid: true
Short(Regex) Way. Character: ” isValid: true
Short(Regex) Way. Character: [ isValid: true
Short(Regex) Way. Character: ] isValid: true
Short(Regex) Way. Character: { isValid: true
Short(Regex) Way. Character: } isValid: true
Short(Regex) Way. Character: $ isValid: false
Short(Regex) Way. Character: H isValid: false
Short(Regex) Way. Character: 1 isValid: false
Short(Regex) Way. Character: * isValid: false

They are functionally equivalent. Now on to performance.

After commenting out the console.log statements the profiler gives the following output:

Testing the long way:
Profile (0.143ms, 17 calls)
containsBadChars 17 100% 0.143ms 0.143ms 0.008ms 0.002ms 0.067ms

Testing the short(regex) way:
Profile (0.047ms, 17 calls)
containsBadCharsRegex 17 100% 0.047ms 0.047ms 0.003ms 0.002ms 0.006ms

As you can see the Regex way is about 3 times faster.

Happy programming!

jQuery Document Ready…use it wisely!

jQuery has done an excellent job with the document .ready() function which allows us to accurately know when the DOM has been loaded so that we can begin processing our JavaScript code. Prior to this we had to rely on the windows onLoad event which tends to occur much later in the load cycle.

Usually, one ready handler per page or view is used as the document ready handler will parse/execute the code once the DOM has loaded. Having this handler process code not relevant to the document at hand would be wasting resources.

Unfortunately I have noticed that this facility is used freely and loosely, even when sometimes it is not required, under the guise of “just to be on the safe side”. Not using this function properly has an impact on the performance of the application.

Consider a very simple example. We have two JS files test1.js and test2.js which are respectively included in test1.php and test2.php. These files are shown below:

test1.php

<html>
<head>
   <title>Test 1</title>
   
   <script src="jquery-1.4.2.js"></script>   
   <script src="test1.js"></script>
</head>
<body>

<div id="testDiv1">
<?php
$rows = 100;
echo    '<table>';
for($i = 0; $i < $rows; $i++){
	echo "<tr>";
	echo " <td>{$i}</td>";
	echo "</tr>";
}
echo '</table>';
?>
</div>
</body>
</html>

and the JS include file test1.js:

(function($) {
   $(document).ready(function(event) {
      console.log('test1.js - Number of tr elements: ' + $('#testDiv1 table tr').length);    
      
      //assume event bindings
      
      //assume processing code
      
   });
})(jQuery);

When run, the php file prints out a table structure with 100 rows. When the DOM is loaded(the table structure in our case) the ready event fires and prints out a message on the console:
test1.js – Number of tr elements: 100

test2.php and test2.js are similar, except this one prints out the number of ‘td’ elements instead of tr.

test2.php

<html>
<head>
    <title>Test 2</title>
   
   <script src="jquery-1.4.2.js"></script>   
   <script src="test2.js"></script>
</head>
<body>

<div id="testDiv2">
<?php
$rows = 100;
echo    '<table>';
for($i = 0; $i < $rows; $i++){
	echo "<tr>";
	echo " <td>{$i}</td>";
	echo "</tr>";
}
echo '</table>';
?>
</div>
</body>
</html>

and the JS include file test2.js:

(function($) {
   $(document).ready(function(event) {
      console.log('test2.js - Number of td elements: ' + $('#testDiv2 table td').length);    
      
      //assume event bindings
      
      //assume processing code
      
   });
})(jQuery);

When run the console prints out:
test2.js – Number of td elements: 100

As long as each JS file with the ready function is included in its respective host file or view everything works as it should without any overlap or conflict. But life is not so simple.

To reduce page load times it is customary to join many files into one and then minify the resulting file. This takes away the performance degradation due to latency issues as only one file is loaded compared to many.

By the same token it is also advisable that JS code specific to a view or a page be loaded per page while common code be bundled together and minified. This leads to a highly efficient load which does not tax the resources and also keeps the latency issues to a minimum.

Recently I came across an open source project based on the MVC pattern which joined 55 JS files, with each file having its document ready function. This bundle included common and specific files. Let me illustrate to you how much of a performance impact this can make. Let’s join test1.js and test2.js into one file and call it test.js. I have not minified this file for the sake of clarity.

test.js

(function($) {
   $(document).ready(function(event) {
      console.log('test1.js - Number of tr elements: ' + $('#testDiv1 table tr').length);    
      
      //assume event bindings
      
      //assume processing code
      
   });
})(jQuery);

(function($) {
   $(document).ready(function(event) {
      console.log('test2.js - Number of td elements: ' + $('#testDiv2 table td').length);    
      
      //assume event bindings
      
      //assume processing code
      
   });
})(jQuery);

Also let’s modify test1.php to include this file:
test1.php

<html>
<head>
   <title>Test with joined JS file</title>
   
   <script src="jquery-1.4.2.js"></script>   
   <script src="test.js"></script>
</head>
<body>

<div id="testDiv1">
<?php
$rows = 100;
echo    '<table>';
for($i = 0; $i < $rows; $i++){
	echo "<tr>";
	echo " <td>{$i}</td>";
	echo "</tr>";
}
echo '</table>';
?>
</div>
</body>
</html>

If we now run this we get the following on the console:
Console [5]=
test1.js – Number of tr elements: 100

Console [6]=
test2.js – Number of td elements: 0

Notice that there are two document ready handlers in test.js, and both ran. This is because when the DOM loads they cannot distinguish a relevant file from an irrelevant one. The first message is valid as it relates to test1.php but the second is not, as it relates to test2.php. This means the effort put in by the JS engine for the second handler was a waste.

Usually the document ready handler does not contain a simple log message, but a slew of event bindings and other JS code. Some of the files in the aforementioned project had close to a dozen event bindings. Even if we were to assume an average of five event bindings per file, that’s 275 bindings. Take into account event bubbling, live bindings and we are talking serious performance problems.

In such circumstances we cannot rescue everything but we can inject a little saving grace.

Here is the same test1.php and test.js with changes, which I will explain in a minute:

test1.php

<html>
<head>
   <title>Test with joined JS file</title>
   
   <script src="jquery-1.4.2.js"></script>   
   <script src="test.js"></script>
</head>
<!-- Note the new title attribute -->
<body title="test1">

<div id="testDiv1">
<?php
$rows = 100;
echo    '<table>';
for($i = 0; $i < $rows; $i++){
	echo "<tr>";
	echo " <td>{$i}</td>";
	echo "</tr>";
}
echo '</table>';
?>
</div>
</body>
</html>

Notice that in the body tag I have added a title attribute.

test.js

(function($) {
   $(document).ready(function(event) {
      //check if for this handler ***NEW****
      var title = $('body').attr('title');
      if(title !== 'test1'){
         return false;
      };
      console.log('test1.js - Number of tr elements: ' + $('#testDiv1 table tr').length);    
      
      //assume event bindings
      
      //assume processing code
      
   });
})(jQuery);

(function($) {
   $(document).ready(function(event) {
      //check if for this handler ***NEW***
      var title = $('body').attr('title');
      if(title !== 'test2'){
         return false;
      };
      console.log('test2.js - Number of td elements: ' + $('#testDiv2 table td').length);    
      
      //assume event bindings
      
      //assume processing code
      
   });
})(jQuery);

If you run this now you will get the following in the console:
test1.js – Number of tr elements: 100

Let me explain why.

In test.php I have added a title attribute which identifies this file

In the JS file I have added the following code in the document ready handler:
//check if for this handler
var title = $(‘body’).attr(‘title’);
if(title !== ‘test1’){
return false;
};

It only continues to processes the handler code if the title attribute matches “test1”. So the handler connected with test2 never continues which saves resources.

The crux of the idea is to make processing relevant to the document at hand. This is only one way of doing it. Many other ways come to mind and I leave them to your imagination.

I hope this helps you and I look forward to your feedback.

Option to select specific tab after removal in jQuery UI.TABS

One of the problems with the remove method of jquery ui.tabs is that after deleting the tab it either selects the tab on the right or if it is the last tab it selects one on the left.

My initial impression was that I could change this behavior by calling the select method in the ‘tabsremove’ event. But that does not work as the default selection takes place before the event is fired as indicated in the source below:

    remove: function( index ) {
                index = this._getIndex( index );
                var o = this.options,
                    $li = this.lis.eq( index ).remove(),
                    $panel = this.panels.eq( index ).remove();
              //DEFAULT SELECTION TAKES PLACE HERE
                // If selected tab was removed focus tab to the right or
                // in case the last tab was removed the tab to the left.
                if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
                    this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
                }
                o.disabled = $.map(
                    $.grep( o.disabled, function(n, i) {
                        return n != index;
                    }),
                    function( n, i ) {
                        return n >= index ? --n : n;
                    });
                this._tabify();
              //EVENT FIRED HERE
                this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
                return this;
            },

So that I could better control as to what was selected after tab removal I over-rode the remove function like so:

$.extend( $.ui.tabs.prototype, {
        remove: function( index, nextIndex) {
              var o = this.options;
         
             index = this._getIndex( index );
         
          //if nextIndex passed use it or use use the default which is follows:
          //If selected tab was removed focus tab to the right or
            //in case the last tab was removed the tab to the left.
          if(nextIndex !== undefined){
             nextIndex = this._getIndex(nextIndex);
          }else{
             if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
                   nextIndex = index + ( index + 1 < this.anchors.length ? 1 : -1 );
             }
          };
        
            //remove this tab
          $li = this.lis.eq( index ).remove();
            $panel = this.panels.eq( index ).remove();
         
        
          //select the next tab
          this.select(nextIndex);
          //make sure to remove the removed tab index
          //from the disabled list
            o.disabled = $.map(
                $.grep( o.disabled, function(n, i) {
                    return n != index;
                }),
                function( n, i ) {
                    return n >= index ? --n : n;
                });
          this._tabify();
            this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
         
            return this;
        }
});

USAGE:
.tabs( “remove” , index, nextIndex )
Example:
$tabs.tab(“remove”, 2, 5); //This would remove tab at index 2 and then select tab at index 5

I hope it helps someone and I look forward to everyone’s feedback.

Also replicated on the jQuery Forum:
http://forum.jquery.com/topic/ui-tabs-remove-method-additional-option-to-select-sepecific-tab-after-removal