Original Version
Maximum concurrent connection to the same domain for browsers
Do you surprise when I told you that there is a limit on how many parallel connections that a browser can make to the same domain?
The limit
Don't be too surprise if you never heard about it as I have seen many web developers missed this crucial point. If you want to have quick figure, this table is from the book PROFESSIONAL Website Performance: OPTIMIZING THE FRONT END AND THE BACK END by Peter Smith
Why browsers have this limit?
You may ask if this limit can have such a great impact to performance, then why don't browser give us a higher limit so that user can enjoy better browsing experience. The browser choose not to do so so that the server will not be overloaded by small amount of browsers. In the past, the common limit is only 2 connections. This is sufficient in the beginning day of web pages as most of the contents are delivered in a single page load. However, it soon become the bottleneck when css, javascript getting popular. Because of this, you can notice the trend to increase this limit for modern browsers. Some browsers even allow you to modify this value (Opera) but it is better not to set it too high unless you want to load test the server. Otherwise the server may classify your IP as DDOS attacker.
The impact of this limit
How this limit will affect your web page? The answer is a lot. Unless you let user load a static page without any images, css, javascript at all, other while, all these resources need to queue and compete for the connections available to be downloaded. If you take into account that some of the resources depend on other resource to be loaded first, then it is easy to realize that this limit can greatly affect page load time.
How to handle this limit?
This limit will not cause slowness in your website if you manage your resource well and not hitting the limit. When your page is first loaded, there is a first request which contain html content. When the browser process html content, it spawn more requests to load resource like css, images, js. It also execute javascript and send Ajax requests to server as you instruct it to do.
Fortunately, static resources can be cached and only be downloaded the first time. If it cause slowness, it happen only on first page load and is still tolerable. It is not rare that user will see a page frame loaded first and some pictures slowly appear later later. If you feel that your resources is too fragmented and consume too many requests, there are some tools available that compress and let browser load all resources in single request (UglifyJS, Rhino, YUI Compressor, ...)
Lack of control on Ajax requests cause a more severe problem. I would like to share some sample of poor design that cause slowness on page loading.
1. Loading page content with many Ajax requests
This approach is quite popular because it let user feel the progress of page loading and can enjoy some important parts of contents while waiting for the rest of contents to be loaded. There is nothing wrong with this but thing is getting worse when you need more requests to load content that the browser can supply you with. Let say if you create 12 Ajax requests but your browser limit is 6, in best case scenario, you still need to load resources in two batches. It is still not too bad if these 12 requests are not nesting or consecutive executed. Then browser can make use of all available connections to serve the pending requests. Worse situation happen when one request is initiated in another request callback (nested Ajax requests). If this happen, your webpage is slowed down by your design rather than by browser limit.
Few years ago, I took over one project, which is haunted with performance issue. There are many factors that causing the slowness but one concern is too many Ajax requests. I opened browser in debug mode and found more than 6 requests being sent to servers to load different parts of page. Moreover, it is getting worse as the project is delivered by teams from different continents, different time zone. Features are developed in parallel and the pair working on a feature conveniently add server endpoint and Ajax request to let work done. Worrying that the situation is going out of control, we decided to shift the direction of development. The original design is like this:
For most of Ajax requests, the response return JSON model of data. Then, the Knock-out framework will do the binding of html controls with models. We do not face the nested requests issue here but the loading time cannot be faster because of browser limit and many http threads is consumed to serve a single page load. One more problem is the lack of caching. The page contents are pretty static with minimal customization on some parts of webpages.
After consideration, we decided to do a reset to the number of requests by generating page contents in one page. However, if you do not do it properly, it may become like this:
This is even worse than original design. It is more or less equal to having the limit of 1 connection to server and all the requests are handled one by one.
The proper way to achieve similar performance use Aysnc Programming
Each promise can be executed in a separate thread (not http thread) and the response is returned when all the promises are completed. We also apply caching to all of the services to ensure the service to return quickly. With the new design, the page response is faster and server capacity is improved as well.
2. Fail to manage the request queue
When you make a Ajax request in javascript and browser do not have any available connection to serve your request, it is going to request queue. Disaster happen when you fail to manage the request queue. This happen when developer build the rich client application. Well, rich client application function like an application more than a web page. Clicking on button does not load new web address, instead the page content is uploaded with result of Ajax request. The common mistake is to let new requests to be created when you have not managed to clean up the existing requests in queue.
I have worked on a web application that make more than 10 Ajax requests when user change value of a first level combo box. Imagine what happen if user change the value of the combo box 10 times consecutively without any break in between? There will be 100 Ajax requests go to request queue and your page seem hanging for a few minutes. This is an intermittent issue because it only happen if user manage to create Ajax requests faster than the browser can handle.
The solution is simple, you have two options here. For the first option, forget about rich client application, using javascript to refresh the page with the value of combo box appear on the hash of web address. Browser will clear up the queue for a page refresh. For the second option, block user from making change to combo box if the queue is not cleared.
3. Nesting of Ajax requests
I have never seen a business requirement for nesting Ajax request. Most of the time I saw nesting request, it was design mistake. For example, if you are a lazy developer and you need to load country flags for every country in the world, sorting by continent. Disaster happen when you decide to write code this way:
Load the continent list
For each continent, loading country
Assume the world have 5 continents, then you spawn 1 + 5 = 6 requests. This is not necessary as you can return a map of list in single return. Making requests is expensive, making nesting request is very expensive, using Facade pattern to get what you want in a single call is the way to go.