Ajax Best Practices: Reduce and Aggregate similar XHR calls
My mobile contract is expiring soon, so I went online and checked the different mobile companies for their offerings. All of these sites have a page where you get an overview of all the different phone models available. One one page I noticed that the list of phones started with an empty grid – and then – slowly – images appeared and after that some overlay information on the phone itself was added (such as a link on the facebook, msn or skype page of the phone manufacturer). From a time perspective it took about 2 seconds till I saw something on the page, after 4 got to see the empty grid and after 15 seconds everything was loaded. That made me curious about the internals of that page.
Analyzing a heavy AJAX Page
I start by using dynaTrace AJAX Edition and browse to the same page (I use the latest Beta build for my analysis). When I am done I go back to the AJAX Edition and open the Performance Report. The first thing I do is check the timeline which gives me an overview of all activities on the page from when I entered the URL until it was fully loaded. The following image shows the timeline of this page:
Analyzing the XHR Calls
All 3 XHR calls return JSON objects where the third call – to retrieve product information – returns an array of 47 products including product name, price information and a product id:
We can see that every handler in the for each loop takes longer to execute and that most of the time spent in each of these loop iterations is waiting for the XHR Request to come back with another JSON object that holds some additional product information. Why this is taking longer with every call? A look at the Network View shows us what the problem is:
The increasing time component is the wait time for every request. A browser only has a limited number of physical network connections it opens to each domain. In my case it uses 2 connections per domain. With a total number of 47 XHR calls and 47 product images but only 2 connections available to make these calls we end up with a very high wait time for each of those requests.
Solution: Reducing network roundtrips by reducing requests
The solution is rather easy – at least in theory. The goal is to reduce the number of network roundtrips. Not only does this save you time lost with network latency – it also saves time on the server as it has fewer requests to handle and it solves the problem in the browser by not needing to wait so long for an open connection as we have far fewer requests. In this case – instead of making one XHR call for every one of the 47 products – I would just make a single call to retrieve the product information in one roundtrip for all of them. Or – even better – just include that information in the initial XHR call that gets the list of products. With that approach we can save 46 or even 47 roundtrips.
This would have a major impact on the web site performance. If we would then also merge the 47 images files into a single file using CSS Sprites we can get rid of another 46 roundtrips. I know – this is the theory – it might be not that easy to implement this on every page based on the architecture or maybe because there is not time or people that could actually do this – but – if I do the math here: instead of waiting 15 seconds till the page is fully loaded I assume the page can be loaded in 6 or 7 seconds. This would accelerate page loading by more than 50% speed up of this page. And – as we have recently learned from Velocity – Speed is Money!!
It is not the first time I’ve seen this exact implementation and therefore I assume it is not the last implementation out there that solves a problem like a product catalogue like this. Be aware of too many XHRs. Reduce the roundtrips. Another solution would be to use different domains for your XHR calls and your images. This gives the browser additional physical connections and speeds up the download. It’s not the perfect solution – but it is a good workaround