Optimizing Internet Explorer JavaScript Performance ASP.NET

Ajax web portals require a lot of Java Script to be loaded in the browser. Because there’s only one page, the more features on the user’s Start page, the more Java Script needed to deliver to the page. ASP. NET AJAX Frame work, extenders, and scripts from wid gets make the browser slower to run Java Script and respond to user actions. If the JavaScript doesn’t follow best practices, such as keeping careful consideration on performance and memory allocation, then the browser starts to crawl after some time. Old browsers, like Internet Explorer 6, are not made to run the large amount of Java Script that Ajax web portals require. This means some times reengineering is needed on your client-side frame work, and sometimes several major components will need to be re written to over come the per formance limitation of browsers.

Re-engineering and re writing is always expensive in the later stage of aproject. So, knowing performance-and memory-related issues with old browsers upfront will save you lot of time and moneyInternet Explorer 6 has the worst performance when it comes to Java Script execution speed and memory leaks; Internet Explorer 7 is much better. Fire fox and Opera provide the best performance on a large amount of Java Script and have almost no memory leak. Un fortunately, IE 6 is still the most used browser in the world. So, the majority of your users will still be using IE 6, which makes it a challenge to deliver a rich user interface to the browser while maintaining speed and reliability. In next sections, we will look at some Java Script performance issues in IE 6 and some major memory leak problems and their solutions.

Reducing IE Symbolic Lookups

A primary source of IE Java Script performance issues is the constant symbolic lookup. Symbolic lookup occurs whenever the Java Script engine tries to pair a name or identifier in the script with an actual object, method call, or property running in the context of the engine. For example, document. write will result in symbolic lookup on document object for the write function. Symbolic lookups are expensive, especially on DOM elements, because IE has to do a lookup on the DOM element’s interface and find the function/property that you need. To improve Java Script performance in IE, the first step is to reduce the number of symbolic lookups and help IE limit lookups to as small scope as possible.

Evaluating local variables

A variable is accessed based on a scope chain that resolves bac kward from the most specific scope to the least specific. Some times these symbolic lookups can pass through multiple levels of scope and eventually wind up in generic queries to the IE DOM, which can be quite expensive. The worst-case scenario is that your variable doesn’t yet exist and every level of scope in the chain is investigated, only to find that an expando variable(a dynamically defined property attached to a DOM element) needs to be created.

Example shows a classic example of a local variable lookup that results in creating an expando on the window object. When you try to access some _ variable, IE needs to see whether it is defined in the test( ) function; if not, it checks the parent function, then its grandparent until it reaches the window object. It then finds that there’s no property named some_variable to window object. So, it creates an expando and assigns the value to it. Next time you try to access that variable, it moves up the same lookup chain, but this time it finds the variable on window object

Symbolic lookup on local variables

The solution to this is to use the var keyword to ensure the variable is created in the local scope only. Example shows how you can force a local variable and thus limit symbolic lookup efforts for IE.

Solution to local variable lookup

Declaring local variables with the var keyword will create fast execution and greatly improve your JavaScript performance if you have mistakenly created a lot of variables without using the var keyword. You can easily see the difference by running both versions of the test( ) function from Examples and inside a loop in a low-end computer and see the difference in their execution times.

This optimization is not IE-specific—other browsers will benefit from optimized code as well if they can do shorter symbolic lookups.

Reducing symbolic lookup on DOM elements

All binding in Java Script is late binding, not early binding like in compiled languages such as C#. Moreover, because Java Script is interpreted and not compiled, the Java-Script engine has no idea what will be next in line to do any compiler optimization. This means that each time you access a property, variable, or method, a lookup is performed. Within the DOM, this could mean an extensive search of the element to find the same property over and over again, only to return to the Java Script engine un changed from the previous request.

In Example, the innerHTML property on a div is accessed several times. Each time, the Java Script engine does a symbolic lookup on the div. The first statement is a plain assignment. But the following statements actually require two lookups each: to get the existing value and to set the combined value.

Example of performance degradation from repeated DOM lookups

In Example , the solution is to build a combined string first and then assign the string to the innerHTML property in a single assignment. This will clear the previous content and set the new HTML.

Faster code by eliminating repeated lookups

Speeding symbolic lookup by caching DOM elements, properties, and functions

Because local variables lookups are the fastest, you can benefit from performance improvement by caching DOM element properties and function references in local variables to access them easily. Local variables maintain a direct reference to the original item (by reference) and do not create or duplicate any item.

In Example, document. body is looked up over and over, which createsrepeated lookups for the body property on the document object. Storing the document. body in a local variable can optimize this performance.

Slow code on repeated DOM lookup

In Example, we have eliminated repeated lookups on the document object, which is a big object. Caching the body object’s childNodes property in a local variable will further optimize the code.

Caching the DOM element reference will make the code faster

Fastest implementation

Not only can you cache the DOM properties but also the functions. Functions are also looked up on every call. If it’s not a local function, then there is an expensive scan for it in the ancestor scopes. You can benefit from caching JavaScript functions as well as DOM element functions like appendChild. Example shows how repeated calls to functions can be optimized.

Repeated calls to functions result in slow performance

Example shows how we can optimize two functions by caching node. append Child and my_function.

Cache functions in local variables


You will benefit from caching DOM properties, as well as your own Java Script functions, especially the ones that are defined at global scope, which is the Java Script engine’s last step in the symbolic lookup to find them. Generally, you will have some utility functions defined at global scope and use those utility functions repeatedly in many places. Caching those heavily used utility functions in local variables will give you some performance boost.

Mitigating Internet Explorer Memory Leak

A circular reference results when a DOM object contains a reference to a Java Script object (such as an event handling function) and that Java Script object contains a reference back to that DOM object. The garbage collector, which is a memory manager, collects objects that are not referenced by anything and reclaims their memory. The Java Script gar bage collector under stands circular references and is not confused by them. Un fortunately, IE’s DOM is not managed by Java Script. It has its own memory manager that does not understand circular references. As a result, when a circular references occurs, the garbage collector cannot reclaim the memory because it does not know whether the Java Script object needs the DOM object. The memory that is not reclaimed is said to have leaked. Over time, this can result in memory starvation. The more IE runs and leaks memory, the slower it becomes. Lack of memory makes other programs page to disk and become slower also. The operating system has too much paging to do between RAM and the page file on disk, so the computer gets slower. You have to close the browser to free up the RAM that IE has allocated and to return to normal operational speed.

Avoid using event handlers as closures

Cyclic reference can happen if global variables holding references to DOM objects or event handlers are defined as closures. Closures are functions that refer to free variables in their lexical context. When closures reference DOM objects, there’s no way to know when that object will be needed, so the object is never freed.

In Example, a closure is formed in the event handler where it references two variables outside its local scope. For example, the closure_test execution function completes and the local variables (img and div) are ready to be released, but the event handler on img needs both img and div to be alive when it is fired. Therefore, the Java Script engine cannot release the reference to the DOM objects. So, there are active references on both an image and a DIV. The IE gar bage collector will not be able to reclaim these elements’ memories even if explicitly removed from the DOM element by calling remove Child. They will remain in the memory forever and never be released, and IE will leak memory.

Example of a closure leaking memory

The first step to avoid closure leaking is to use the this keyword to refer to the element that fires the event. Example shows improvement in one step.

Preventing the image from leaking

Now IE can release someImage but not someDiv as the closure still holds the reference to the DIV. There are two workarounds to this problem:

  • Get the DIV inside the event handler using its ID (if the ID is known at this stage)
  • Store enough information to resolve the DIV from within the event handler if ID is not known (see Example)

Leak-free event handling

Use out-of-scope functions

However, there’s an even safer and better approach to event handling—out-of-scope functions. This ensures the callback function will never be able to hold onto any reference to local variables within the main function.

Example shows that by declaring the event handler function out of the scope, there’s no way the function can hold onto any variable reference inside the closure_step3 function.

Using out-of-scope functions for event callback

A . NET developer might think that Example is how C# code is written for event handling. But closures are the norm for event handling in Java Script. Most popular frameworks, such as Prototype, Dojo, and jQuery, and utility libraries like Script. aculo. us, are full of closures. Closure gives Java Script developers a powerful syntax to reduce code size significantly, so they are familiar with using closure for many purposes including event handling.

The best way, however, is to use ASP. NET AJAX Framework’s $addHandler and $removeHandler functions to subscribe/unsubscribe to events on DOM elements because they provide cross-browser implementation to work safely with events:

$addHandler
Subscribes to a specific event multiple times; when the event is raised, it fires the event handlers one after another. You generally call it using an out-of-scope function and avoid the closure problem.

$removeHandler
Removes a specific handler from an event but leaves other handlers intact.

$clearHandlers
Removes all event handlers from an element, marking it safe to be reclaimed by the garbage collector (see Example ).

Using $addHandler and $removeHandler

function closure_safer( )
{
var img = document. getElementById('someImage')

Using $addHandler and $removeHandler (continued)

It is a good practice to remove all event handlers when you are done with an element. This ensures IE can collect the item properly. One thing to note: you can use $removeHandler and $clearHandler only when you have used $addHandler on an element.

Example shows a new function—$clearEvents—that calls the ASP. NET AJAX Framework’s $clearHandlers function to clear any event attached by $addHandler and then sets the common event handler properties to null. This ensures that all event handlers are cleared.

Backward-compatible $clearEvents

Remove DOM elements

To reduce memory leaks, you will have to remove unused events from DOM elements. However, it’s always difficult to keep track of DOM elements and ensure they are released properly. So, one handy way to clean up DOM elements and make them ready for the garbage collector is to remove all event handlers during the window. on unload event. There are some common elements where events are generally attached, e. g. , DIV, input, select, and hyper links. So, if you call $clearEvents on all such nodes, you can get rid of the majority of event handlers and make them safe for removal (see Example).

Safe way to release DOM elements during window. onunload

The window. on unload event is fired right before browser is closed or the user navigates away to a different page. During this time, cleaning up a majority of the event handlers will ensure you have removed as much of the memory leak as possible. However, expandos attached to DOM elements need to be released. It is difficult to find these expandos because you have to run through each and every property of a DOM element and set it to null.

Browsers will get stuck for several seconds if you do this for all DIV tags or all hyperlinks. There’s not much you can do about this, except hope most of the memory leak was resolved by removing the event handlers.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

ASP.NET Topics