This is part 14 of a multiple part series on web performance improvements. The first Introductory blog can be found here. In previous part we discussed the pro and cons of putting style sheets at top of the HTML page. In this part we will why we should always prefer to put the script (js) files at bottom of the HTML document.
Whenever user request a webpage, the biggest impact on response time is the number of components in the page. Each component generates an HTTP request when the cache is empty, and sometimes even when the cache is primed. Though the browser performs HTTP requests in parallel, the browser cannot download them all at once. The explanation goes back to the HTTP/1.1 specification, which suggests that browsers download two components in parallel per hostname. Many web pages download all their components from a single hostname. Following figure shows a generic request-response pattern.
If a web page evenly distributed its components across two hostnames, the overall response time would be about twice as fast. Most of the browsers follow the guideline by default, but users can override this default behavior. For example Internet Explorer stores the value in the Registry Editor. You can modify this default setting in Firefox by using the network.http.maxpersistent-connections-per-server setting in the about:config page. It’s interesting to note that for HTTP/1.0, Firefox’s default is to download eight components in parallel per hostname. Most web sites today use HTTP/1.1, but the idea of increasing parallel downloads beyond two per hostname may backfire. Instead of relying on users to modify their browser settings, frontend engineers could simply use CNAMEs (DNS aliases) to split their components across multiple hostnames. But maximizing parallel downloads may cost dearer in many cases. Depending on bandwidth and CPU speed, too many parallel downloads can degrade performance. Research shows that splitting components across two hostnames leads to better performance than using 1, 4, or 10 hostnames.
Scripts Block Downloads
The benefits of downloading components in parallel are clear. However, when the browser is downloading a script it will disable parallel downloads. The browser won’t start any other downloads, even on different hostnames. Some reasons for this behaviour are as follows:
- The script may use document.write to alter the page content, so the browser waits to make sure the page is laid out appropriately.
Issues with scripts at the Top
If the scripts are placed on top of any web pages fowloing issues will happen, which will hurt performance of the page as well as user experience.
- Everything in the page is below the script, and the entire page is blocked from rendering and downloading until the script is loaded.
- All components below the script are blocked from being downloaded.
- Because this entire page is blocked from rendering, it results in the blank white screen phenomenon. Progressive rendering is critical for a good user experience, but slow scripts delay the user’s feedback.
- The reduction of parallelized downloads delays how quickly images are displayed in the page.
Scripts at Bottom
The best place to put scripts is at the bottom of the page. The page contents aren’t blocked from rendering, and the viewable components in the page are downloaded as early as possible. So all the issues faced due to script on Top can be solved by putting script at bottom.
Other practical scenarios
It is possible for a script to take longer than expected and for the user’s bandwidth to affect the response time of a script. Having multiple scripts in your page compounds the problem. In some situations, it’s not easy to move scripts to the bottom. If, for example, the script uses document.write to insert part of the page’s content, it can’t be moved lower in the page. There might also be scoping issues. In many cases, there are ways to work around these situations.
An alternative is to use deferred scripts. The DEFER attribute indicates that the script does not contain document.write, and is a clue to browsers that they can continue rendering. Unfortunately, in Firefox, even deferred scripts block rendering and parallel downloads. In Internet Explorer, components lower in the page are downloaded slightly later. If a script can be deferred, it can also be moved to the bottom of the page. That’s the best thing to do to speed up your web pages.