Apr 12 2010

The curious case of "Stop running script" error & jQuery

Category: NovoGeek @ 05:39

Before starting with the article, I would like to share something which encouraged me a lot. Now I'm a Microsoft Most Valuable Professional (MVP) for ASP.NET. Thanks to Microsoft folks for recognizing my efforts. :)

 

Coming to the point., have you ever faced the below “Stop running script” error message in your thick client web apps? This is one of the most frustrating errors, which hangs the browser, spikes CPU usage and slows down your operations.

 

 

Nicholas C. Zakas has an excellent article on why it occurs in various browsers. In short, his research says that the error occurs in various browsers due to exceedingly high number of operations taking place(~5 million statements in IE), or due to script executing for a very long time(~10 secs in FF).

For best performance, Nich says that no script should take longer than 100 ms to execute on any browser, at any point of time.

 

Now, why should jQuery developers worry about this?

They should, because jQuery is made of nothing but JavaScript and chances of getting this error are more, if you don't understand the core methods properly. Let's see in detail what this means.

 

Take the below script as example. Execute in Firebug console or in IE8 script panel or simply copy/paste in a html file and open it.

(function exec(){ 
    var str=''; 
    for(i=0;i<10000;i++) 
    { 
        str+='<div>test div '+i+'</div>'; 
    } 
    $('body').append('<div id="TestDiv"></div>');
    $('#TestDiv').html(str); 
})();

Note: The above code might crash your browser. So please try in stand alone instance. If you are not getting the error or experiencing different behaviour, probably you have better CPU which does not spike up to 100% for this code. The point here is about wrong usage of code. So increasing the max condition should give the error. This analysis is as per jQuery version: 1.3.2.

 

What I'm doing here is pretty straight forward. Just looping and creating 10000 elements and injecting them into the DOM. Now, what's so important here?

It's just a simple piece of code. 10000 operations in a loop is way beyond the threshold of 5 million operations. When you run this code for the first time, browser stops responding and when you run this for the second time, you get the 'stop running script' error.

 

This might sound silly at a first glance. Such huge loops will obviously cause such errors. But what if you are doing this in your code without your knowledge? Do you know that this error occurs in several facebook apps & in twitter? There is something beyond the loop.

 

$().html vs element.innerHTML:

Replace the line:

$('#TestDiv').html(str);

with this one:

$('#TestDiv')[0].innerHTML=str;

and now try. We are using native JavaScript's innerHTML to inject DOM elements. This is faster than jQuery's .html() and hence no error.

 

Does this mean this is the mistake of jQuery?? No! It's purely developer’s ignorance. First of all, such huge DOM manipulations should not be made (This is commonly used, unknowingly.). Then, you should be aware of what .html() does.

 

$(‘selector’).html() internally removes event handlers attached to every child element in the selector’s DOM tree , cleans up the incoming mark up by adding unclosed tags and then injects the new mark up. So for the first time, since no DOM elements were there, .html() only cleans the new mark up and injects it. For the second time, it has the additional task of removing the event handlers and hence the number of operations are increased, giving the error.

 

So when should I use .innerHTML and when should I use .html()?

Genuine doubt! Use .innerHTML if you are SURE that you have to JUST replace the mark up, provided your mark up does not contain any events attached to it. Use jQuery’s .html() when you want to unbind events attached to elements and take care of garbage collection/memory leaks. (You may refer to “jQuery cookbook” for more info on this).

 

This is not the only pitfall. JavaScript’s native for(;;) loop is faster than jQuery's $.each() loop. So before enjoying the benefits of the library, analyze the bottle necks too.

 

(Q) When does such scenarios arise? Why would someone loop some 10000 times in their code?

(A) Though practically no developer loops ten thousand times in his code, knowing that it’s a performance issue, people tend to make this mistake unknowingly. The analogy here is about larger DOM manipulations. I shall explain such scenarios in my next article.

 

Happy coding :)

Tags:

blog comments powered by Disqus