Alois Reitbauer About the Author

Performance Antipatterns in AJAX Applications

Several years ago JavaScript was seen as a „playground“ due to compatibility problems with browsers and high maintenance costs. Under the term AJAX JavaScript made the breakthrough in the last years. One of the reasons is the availability of libraries and better support of the major browser platforms. Prototype, script.aculo.us and jQuery are under the most well-known frameworks which solve the browser compatibility issues within their libraries.

This post covers 3 major areas of JavaScript performance. Distributed Communication – a core part of AJAX – can help reduce transferred data content. At the same time communication between distributed systems is one of the biggest sources of performance problems.A second aspect is JavaScript based widgets that allow browsers to catch up with Rich Clients in terms of usability. Different JavaScript Frameworks offer nice visual effects implemented with heavy JavaScript using timers and DOM manipulations. However these effects can result in poor usability if e.g.: the expansion of a visual area takes several seconds.Last, but not least we will address the topic of memory leaks. Some memory problems are similar to those on the server-side. Some problems  are caused by the specifics of the JavaScript language. Additionally garbage collection is not as mature as it is Java or .NET virtual machinges. Some of these problems are also related to browser specific implementations of the JavaScript runtime. Fortunately, correct usage of JavaScript frameworks ensure that you do not ran in many of these problems. However as soon as you start to write your onw JavaScript code it iss essential to be aware of the possible problems.

AJAX = DOM + JavaScript + XHR

Let’s start by taking a look behind the scenes of a modern AJAX application. In the figure below you can see the basic structure of an AJAX Application. The core of each website is HTML , in the AJAX field its however the DOM (Document Object Model) that we care about. The Document Object Model defines the hierarchical structure of the displayed website and is comparable with the structure of an XML Document. Accessing the DOM – read or write – is a central concept in AJAX. Similar to traditional UI development controls can be added and event listeners can be registered. How much of the DOM is actually build based on downloaded HTML and how much is generated dynamically depends on the used frameworks. These are however  critical aspects for application performance. dynaTrace AJAX Edition provides detailed insight how DOM manipulations affect redering times

Besides the DOM we have the JavaScript engine. The engine is responsible for code execution. The JavaScript engine is single threaded compared to the Java VM or .NET CLR. That means that all activities in the application share the same thread. This can have a huge impact on application responsiveness. In many cases  timers are used to implement Pseudo-Parallelism.  Frameworks takes away this burden as they handle this internally. When designing an application you have to consider these limitations and therefore prevent long running working routines. A  frameworks like Google Web Toolkit (GWT) that translates Java code into Javascript might not unveil those problems during development time as only Java code is executed.

The XMLHTTPRequest (XHR) Object is a core component of an AJAX Application. It enables communication with the server. The communication is asynchronously. Before sending a request callbacks can be registered to e.g.:  when the response has been received from the server. Communication in the browser come with the restriction of a limited amount of of available physical network connections. The HTTP/1.1 specification specifies that a client should not have more than 2 persistent connections to a server. Fortunately most browsers actually allow 4 connections. These are used to satisfy all network requests for a page request including JavaScript files, images … This highlights a classical bottleneck. Even though frameworks can provide help on this you want to be careful with too many embedded objects. Loading many embedded images dynamically and sending AJAX Requests at the same time can have major impacts on overall application performance. Specific behaviour and limitations of individual browsers can easily be tested with Browserscope. As the connection limit is bound to a server host name using multiple host names is a possible solution.

The next part of an AJAX Application are CSS stylesheets and layout declarations. They can easily become performance relevant when the contain layout declarations contains complex relative position definitions the browser can spend long times with rendering. Other embedded resources and images are performance relevant due to their size and occurrence. Using HTTP Expires and eTag Headers can greatly improve performance of embedded objects by leveraging client side caching.

Schematic overview of an AJAX Application
Schematic overview of an AJAX Application

AJAX Nomen est omen?

If you trust the name then AJAX – Asynchronous JavaScript and XML – is a protocol for asynchronous distributed communication using XML. AJAX however is no protocol – it just describes a concept of communication. HTTP is used exclusively as transportation protocol. Alternatives like WebSockets – as part of HTML 5 – are however already on the horizon. Kaazing for example provides a WebSockets implementation.

The X in AJAX – although anticipated – does not necessarily stand for XML. XML is supported by most JavaScript frameworks. As parsing and modifying XML in JavaScript is expensive and slow it is often not used. JSON – JavaScript Object Notation – is easier to handle and often the preferred choice. As JSON represents valid JavaScript code it can easily be executed with a call to eval. Put easy – JSON defines object arrays or maps name/value pairs in JavaScript. JSON enabled libraries like Jettison and JSONTools make it easy to read and write JavaScript objects.

But that’s not the end of our possibilities. The response of an AJAX request can be any type of text (as is XML and JSON). Some frameworks actually send HTML as response. This HTML can be used directly with the DOM API by setting the innerHtml property. This approach makes sense if XML would be converted to an HTML table anyway. In this case HTML can be directly generated on the server side. Some of you may object that this validates the Model-View-Controller concept – well – this is a matter of personal preference. For some JavaScript developers and frameworks replacing HTML is a pragmatic approach. In case you use frameworks there is only very limited – or none – possibility to influence this behaviour.

Finally we can also send JavaScript as response. Why does this makes sense? Let’s take an online betting system as example. While current games don’t change – the quotes for these games change constantly. Whether we use XML or HTML to update the quotes – too much data is sent to the browser. Per game only one quote is changed – the other values are still the same. Using JavaScript in the response allows only modifying those values that have really changed. The same can also be achieved with JSON and JavaScript.

Very often it’s not up to the developer to decide on the data format. When evaluating frameworks the underlying format and technique should be taken into consideration. In order to find out what data is sent by a framework diagnostics tools like dynaTrace AJAX Edition or simple HTTP Proxy tools like Fiddler can be used to analyze the traffic flow and content.

Who Bayeux … so you are french?

Web applications are based on the request/response pattern of HTTP. This prevents servers to send data to the client if the client is not actively requesting it. The Bayeux Protocol offers a server push communication solution for this problem.The Bayeux Protocol defines using a so called “Long Polling” approach. HTTP requests sent from the client are on hold on the server till the request can be fully answered. This makes implementations of  chat- or ticker applications easy. With a concept similar to JMS Topics a publish/subscribe model can be implement with this protocol.

Server side implementations need to use non-blocking IO (NIO) to guarantee an efficient implementation. The application is notified using events when new data is available. This is supported by Tomcat 6, Jetty and commercially available servers from Oracle and IBM. A sample for a server side implementation can be seen in the Tomcat Documentation.

As explained in the beginning – the number of network connections to a host is limited. The number of actual connection is however not purely depending on the server but also on any eventual proxy. By default one can assume to have 2 connections making the connections a precious resource as blocking connections limit the download of additional data. “Open late – close early” should be used as a general design concept.

I spy with my little eye …

What do you see as a user of a web application? You see a graphical representation of objects in the DOM that are displayed by the rendering engine according to layout definitions. For JavaScript applications there is more to the DOM than you can see. Next to the JavaScript nodes – that are evaluated by the JavaScript engine – there are many hidden elements for instance used for visual effects. It doesn’t matter in these cases whether the DOM tree was complex after the initial page load or whether it became complex after dynamically adding DOM elements as a result of an AJAX requests.

CSS Selectors are used in JavaScript to find elements in the DOM tree needed for manipulation. Complex lookups in large DOM trees require more time. Frameworks try to optimize selectors but queries like “Find all paragraphs in table cells with a first heading of colour red” (#content td:first-child h1[class~=”red”]+p) are potential performance problems and should be simplified as much as possible. More information about possible CSS Selectors can be found in the documentation of the JavaScript Frameworks or in the W3C specification.

Bigger problems come with bigger DOM trees. Every manipulation in the tree triggers new rendering by the browser. Depending on the used CSS a full redraw of the whole DOM might be required if e.g.: position and size of an element depends on surrounding elements. When replacing content via innerHtml the browser even needs to reparse the resulting HTML.

Memory leaks – even in the browser

In the past – when JavaScript was hardly used – the JavaScript engines were good enough. The intensified usage resulted in new requirements. The new V8 Engine in Google Chrome focuses on these new requirements that cover performance and several other aspects. A good example here is the Garbage Collector. JavaScript Garbage Collectors are inferior to their Java or .NET pendants. This leads – sometimes caused by the actual GC implementation – to memory leaks.

The probably most well known memory leak can be found in Internet Explorer (prior to version 8). Reference counting is used as garbage collection strategy. This approach has the problem of circular references – references that in the end refer back to the same object. A specific problem here is references from the JavaScript world into the DOM world. This can easily happen when registering a JavaScript functions as event handlers on DOM objects and also holding a reference to this object. This problem can easily be worked around.

If you have the option to select a browser of choice for e.g.: Intranet applications make sure to select the browser based on known problems. If you plan to replace a Client/Server Application with an AJAX Application the choice of the browser must be part of the part of the technical evaluation process. With the spread of AJAX and the additional problems that come with it it’s recommend to test applications on potential memory leaks with different browsers.

Don’t Closure your eyes!

A special type of memory leak are leaks based on wrong usage of closures. These are specific to JavaScript as this concept doesn’t natively exist in language like Java right now – an implementation might be available in Java 7. A detailed description of Closures can be found here. Let’s have a closer look at Closures so that we can understand the problem. Every function in JavaScript has an execution scope. An execution scope contains all variables of the calling methods and its own. So far there is no difference to Java. Let’s have a look at a sample:

function doStuff (AJAX response){
  var myElems = // newly created elemens in dom
  for … // interate over elements 
    myElem.onClick= function (){
    // do something if someone clicks
  }
}

This code looks fine?  The problem though is that the execution scope of our anonymous onClick function holds a reference to the variables of doStuff.  This includes the AJAX response and – even worse – the array of all created DOM elements. The event handler exists as long as there is at least one element left preventing garbage collection. The problem can easily be fixed. We define the function in advance and not inline. With that we solve the first scope problem. Second of all – we explictly call delete on myElems (or set it to null). That frees up the references and allows proper garbage collection.

Pseudoleaks

A pseudo memory leak that we see more often are incorrectly used CSS Sprites. The concept of sprites comes from the ancient times of game development: Instead of loading many images a single larger image is loaded showing only the relevant section. Using image compression the resulting image is most often smaller than the sum of the individuals. The problem however is that many sprites are most often not used because certain areas in the image stay blank or those partial images are just not used by the application. The browser however needs to load the full image in memory – and that in the uncompressed form of 3+1 byte per pixel.

Another pseudo leak can be seen in server-side push frameworks. These frameworks constantly push data to the client. Some implementations use hidden frames and partial content responses by the server. That means that the server sends information sporadically from time to time. Most often the content is JavaScript. The page of the frame therefore keeps growing the more data is sent to the client. Applications that run all day long can therefore run into massive memory problems. The application therefore needs to be restarted from time to time. Newer versions of frameworks hopefully solve this problem. Its recommended to analyze the “How” when using a Push approach.

Let us now look into several anti-patterns in the AJAX space

Antipattern – too much data

XHR should only transport the required data. Even though XML serialization is fast enough on the server (Java) side processing the data is considerable slower on the JavaScript side. Using JSON is easier and faster for JavaScript. You also save on serialization time when only transferring the requested attributes of objects. Tools like FireBug or dynaTrace AJAX Edition allow you to analyze the transferred data.

The problem of sending too much data also can occur  for the HTTP request. The HTTP specification requires existing cookies to be sent with every request. That also holds true for AJAX requests even if the cookies are not required for processing the request. Cookies are even sent for requests to images or style sheets. That’s why the Yahoo Performance Rules recommend those requests to be handled on its own domain or subdomain that doesn’t use cookies.

Antipattern – Everything or … everything

AJAX is great for dynamically loading data on demand – but it has to be done right. Loading an empty table and then adding 1000 cells per AJAX will very likely lead to performance problems. It makes more sense to use “n+2 Lazy Loading”. The initial page load contains the elements in the visible area of the table (e.g.: 10 elements).

A set of additional elements (another 10 in that scenario) is also already on the page but not yet displayed. When the user scrolls to the next set AJAX can download the next set of elements without displaying them already. Additional data sets can be preloaded on demand. It is also important to remove data sets that are no longer viewed by the user in order to avoid memory and performance problems of too many DOM elements. This intelligent Lazy Loading also solves the problem of functional synchronization as the user does not need to wait for the triggered action. This technique is also called “Prefetching” or “Preloading”. Yahoo uses a similar strategy to preload images and CSS of the search result while the user is still typing the search string.

When processing large data sets it is often more efficient to support the user with functionally adjusted searches to be more effective when searching for data. This avoids unnecessary loading of data that is not needed anyway. Large eCommerce websites like eBay optimized this area to prevent this problem. The idea is “the better the initial result, the less scrolling and browsing is required”.

Antipattern – Interactivity overdosis

A common use case for JavaScript and AJAX is input auto completion. You should not call the server for every keyUp but more like 200-300ms after the user typed the last key. A particular problem is that the sequence of responses is not determinable. The results for the 2nd request could come after the one for the 3rd. Some frameworks have solutions for this problem. RichFaces for instance has an AJAX Event Queue or jQuery has an AjaxQueue Plugin. For frequently used fields we can also use a hybrid approach: a selection of the most common auto completion results can be pre-loaded and displayed without having to request them.

Another reason for high CPU utilization is extensive use of timers. As JavaScript is single threaded, timers are used to implement parallelism. Many parallel running timers result in huge overhead. The JavaScript engine can be relieved by using less and more unified timers that can be used for different tasks.

Antipattern – Underestimated network latency

Distributed communication is one of the key sources for performance and scalability problems. With AJAX it is even more critical to focus on efficient communication. The roundtrip of a request starts in the browser, passes different networks, proxies and gateways and finally ends up at the server. The responde then takes the same path. Technically these requests are handled asynchronously. The end user however perceives it synchronously as he waits for the final result. The usage of AJAX does not change the functional synchronism.

There are several things in the remoting area that have to be considered to make network communication more efficient. A critical point here is the transferred amount of data. This should be as less as possible. On the server side you can make sure that data can be efficiently limited. This can for example be done in data queries by specifying the number of returned data sets as well as specifying a data offset.

Depending on the content AJAX requests should be cached – ideally in the browser. That’s often not as trivial as it sounds. Browsers often cache too much and prevent identical requests to the server. Frameworks have mature mechanisms to prevent caching so that requests definitely make it to the server. It’s recommended to read the frameworks documentation regarding caching options.

The serialization and de-serialization effort is another aspect to look into. We discussed different options of transferring data. Depending on the use case it may make sense for the server to return HTML to avoid the serialization overhead.

Conclusion

Performance problems exist in AJAX Application just as they exist in “traditional” web applications. The source of problems is communication and data transfer, complex DOM interactions and memory problems. Even browsers fight with performance problems – though they rapidly improve their underlying engines. Micro optimizations are therefore not the way to go. It is recommended to use standards and frameworks that enable switching to other or newer browser faster. Sticking to patterns and best practices prevent running into classical rich client antipatterns. In case of performance problems you can use a range of free available tools like YSlow or Firebug. Especially for performance optimizations for Internet Explorer you should look into the free available dynaTrace AJAX Edition.

Credits

Contents for this article were originall created together with Fabian Lange of codecentric for our performance series in the german JavaMagazin

Call for Action

We at dynaTrace started the development of a FREE  performance management solution specially for AJAX applications running in Internet Explorer. Learn more at ajax.dynatrace.com.

Comments

  1. A nice and effective solution that provides great performance (very rich gui) with extremely lean delivery (translating to drastic reduction in net traffic and servers load) is provided by Bindows.

    An even more radical solution that provides rich, interactive visual Ajax for data of huge size (even infinite) is InfiView (www.InfiView.com) – utilizing a unique memory management technology.

  2. Hayden Steep says:

    What’s an antipattern here?

    If a pattern is a common solution to a common problem, then wouldn’t an anti-pattern be a custom solution for a specific type of problem that is not addressed by a regular pattern?

    Try to understand the words you are using. Thanks.

  3. Marty Hill says:

    What’s an antipattern here? See Wikipedia:
    http://en.wikipedia.org/wiki/Anti-pattern

  4. Stephen Hyland says:

    Overall, the article was weak and full of generalisations. The notion that you should limit data sent in ajax, especially to two pages of data, is absurd.. I regularly zip up 10000 records and send them to the browser in a second. Then the browser can handle all sorts of viewing without comminication with the server. Another similar paradigm is downloading entire datasets. I wrote a pharmacy application where the doctors, hospitals, and pharmacists for Ireland were downloaded. Since the data changes only every few weeks it makes sense for the browser to have a copy in its cache. And it only takes, again, a couple of seconds. The browser manipulates and renders the dat in tables, It also searches for strings like doctors names or latitude and longitude coordinates close to a town.

    When one considers the enormous amount of data Google maps, the de-facto standard AJAX application, downloads, it really is sad to hear supposed experts talk about downloading 20 elements of data at a time.. How pathetic.. More like 20k rows of data. Perhaps the author is new to Ajax or hasn’t taken many measurements. Also, if you have the whole database in the browser, when the user is typing, you can instantly display the pharmacist or doctor list just as in a conventional application.

  5. Alois Reitbauer Alois Reitbauer says:

    Stephen,

    if it works to load all the data in advance and then manipulate it only in the browser, this is definitely a good way to go after. How big was the actual dataset sent to the browser? Did you work with ETags or Expires Headers. I think in your case ETags work better as you will not know in advance when the data changes.

    I also see you point of using the browser cache. I am using the same approach for search results. Putting them in the cache avoids unnecessary roundtrips when users navigate back and forth.

    The applications we saw so far suffered from a lot of data being sent and then processed in the browser although rarely needed.

  6. Sometimes a query could take long time, if limited without db cache could take long time for each page.

    In a specific case I found a “key solution” to load in a go 1000 or more table rows via gzipped JSON and rendered 10 after 10 with a client pagination and without any Ajax call rather than 100 servers calls for each “display 10″ page as is in a full Ajax approach.

    Moreover, if not rendered in the DOM JavaScript can handle without problems thousands of “rows”, as array objects, allowing common filters such multiple columns sort, search, filter, etc, via the full set, rather than a different query for each filter/sort, whatever we need, stressing the server without a reason. In this case we could have a slightly greater loading time, nullified by the total amount of real-time operations we could perform in that massive result set … so we are really spreading computation rather than centralize it into the server … but of course we need to know JavaScript a bit better than just a library to take out the best of it.

    As summary, there are always cases and cases and no universal truth about performances best practices, but it is obviously a good thing to talk about them, so thanks.

    Regards

  7. A cache is crucial if your working with a huge database. If it’s serving users then it can be a good idea to have caches for each user.

  8. Good article. Agree with Grant’s comments though.

Trackbacks

  1. [...] This post was mentioned on Twitter by dynaTrace software and Franz See, Frank Cohen. Frank Cohen said: RT @dynaTrace: Performance Antipatterns in AJAX Applications: years ago JavaScript was seen as a „playground“ due to c.. http://bit.ly/7OqB2 [...]

  2. [...] Several years ago JavaScript was seen as a „playground“ due to compatibility problems with browsers and high maintenance costs. Under the term AJAX JavaScript made the breakthrough in the last years. Here is the original: Performance Antipatterns in AJAX Applications [...]

  3. [...] topic of my session is ”Trace Down JavaScript & AJAX Performance in IE”. I will talk about how to analyze Web Site Performance focusing on JavaScript [...]

  4. [...] Performance Antipatterns in AJAX Applications Performance, Scalability and Architecture – Java… – This post covers 3 major areas of JavaScript performance. Distributed Communication – a core part of AJAX – can help reduce transferred data content. At the same time communication between distributed systems is one of the biggest sources of performance problems.A second aspect is JavaScript based widgets that allow browsers to catch up with Rich Clients in terms of usability. Different JavaScript Frameworks offer nice visual effects implemented with heavy JavaScript using timers and DOM manipulations. However these effects can result in poor usability if e.g.: the expansion of a visual area takes several seconds.Last, but not least we will address the topic of memory leaks. Some memory problems are similar to those on the server-side. [...]

  5. [...] about Website traffic as of December 14, 2009 Performance Antipatterns in AJAX Applications – blog.dynatrace.com 10/14/2009 Several years ago JavaScript was seen as a „playground“ due to [...]

  6. [...] Performance Antipatterns in AJAX Applications Performance … [...]

  7. [...] problem patterns in Web 2.0 Applications are similar to Web 1.0 Applications but they have a different impact on overall performance as the [...]

  8. [...] in Ajax Applications was accepted – so I have the honour to share the knowledge about JavaScript/AJAX Performance that we built up – especially since dynaTrace AJAX Edition has been around. The focus of this [...]

  9. [...] Performance Antipatterns in AJAX Applications [...]

Comments

*


one + 2 =