Client-side scripting blocks subsequent downloading and rendering. Even if the <script> tag follows everything else, it still blocks onload. This makes the webpage appear to load more slowly because it delays the point of interactivity. As much as possible, serialize the following actions when loading a webpage:
- Download and execute the needed-nowscripts.
- Wait for onload.
- Download and execute the needed-soonscripts.
- Wait for execution to complete.
- Download and execute the maybe-needed-laterscripts.
- Wait for execution to complete.
- Download and execute the scripts that are likely to be needed on the next page.
In 2009, Steve Souders showed us that older browsers stop parsing when they get to a script. They download the script and execute it in its entirety before continuing. This delays the downloading of other scripts, CSS, and everything else. Page rendering is completely halted.
Newer browsers behave somewhat better, but they’re not perfect. Even if we can guarantee that every user is using an up-to-date browser, we still cannot escape all serialization. This was still an issue in November 2010, when Aaron Peters discovered that his web pages were taking up to 140 seconds to fully load. Although he had taken steps to deal with the problem, he discovered the hard way that third party scripts were loading other scripts, and those other scripts were serially blocking onload.
Many articles and books have been written on this subject since 2009 as the technical community explored various solutions. The following steps are based on those discussions.
If the cache expiry dates of the scripts within each file are too different, that file can be split into smaller files, each with its own expiry date.
#4 Use the technique described below to download and execute the second .js file after the page is fully loaded.
#5 Download and execute the third .js file serially after the previous one has finished executing. This can be accomplished by loading the third file as a callback from the second file. Callbacks are demonstrated in Nicholas Zakas’ loadScript function.
#6 Now that everything is taken care of for the current page, download the script(s) for the next page(s) the user is likely to visit. Once again, complete the needed-now files before the needed-soon files. This step assumes that the files contain no top-level code (i.e., functions only).
How to Download and Execute After Onload
There is one gotcha here, though. Before calling any of the functions in the downloaded file, we must first ensure that it has been fully downloaded and processed. After all, we can’t call a function that hasn’t been created yet. Nicholas Zakas shows how to incorporate callbacks into the above code so that the callbacks are executed after the script file is fully loaded and has completed execution. His technique can be used to make sure functions exist before they are called. [The code shown above is a KISS teaching tool that simply shows the basic concept; Nicholas Zakas’ article presents something more useful for real-world development projects.]
One final note: Files downloaded this way cannot use document.write, so we’ll have to go through the DOM tree instead. Warning: We must be careful not to change the sizes or locations of page elements. When the layout of elements changes, pages appear to jump around while the user is trying to interact with them.
Async & Defer
The relatively new async and defer attributes can be used in a <script> tag to execute the script asynchronously now or later.
Using the technique described above is recommended over the use of async or defer because the standard for these new attributes says nothing about when to download them or insert them into the DOM tree. Also, using these attributes will block onload.
For Further Research
For those so inclined, here are a couple of topics that could use a little more investigation:
- Most authors agree that <script> tags should be placed immediately before the </body> tag, but this guarantees serialization because downloading and executing the script will wait until everything else is finished. Is there a way to put the script tag in the head and have the download occur asynchronously with everything that follows, but at a lower priority level? The async attribute comes to mind, but its standard does not say that downloading is asynchronous, only its execution. And it downloads and executes at the same priority level as everything else.
Best Practices for Speeding Up Your Web Site by Yahoo’s Exceptional Performance Team. Published by Yahoo at developer.yahoo.com/performance/rules.html. Accessed 2012.01.13.
Even Faster Web Sites: Performance Best Practices for Web Developers (ISBN 978-0-596-52230-8) by Steve Souders. Published June 2009 by O’Reilly Media.
High Performance Web Sites: Essential Knowledge for Front-End Engineers (ISBN 978-0-596-52930-7) by Steve Souders. Published September 2007 by O’Reilly Media.
HTML5: A vocabulary and Associated APIs for HTML and XHTML: The Script Element (Editor’s Draft). Published 2012.01.13 by the World-Wide Web Consortium at dev.w3.org/html5/spec/the-script-element.html. Accessed 2012.01.13.
Loading Scripts Without Blocking by Steve Souders. Published 2009.04.27 by Steve Souders at SteveSouders.com/blog/2009/04/27/loading-scripts-without-blocking. Accessed 2012.01.13.
Monitis Free Page Load Testing Tool. Published by Monitis at pageload.monitis.com. Accessed 2012.01.13.
Monitis Transaction Monitoring. Published by Monitis at portal.monitis.com/index.php/products/transactions-monitoring. Accessed 2012.01.13.
Performance on the Yahoo! Homepage by Nicholas C. Zakas. Published by SlideShare.net at www.slideshare.net/nzakas/performance-yahoohomepage. Accessed 2012.01.13.
Performance Research, Part 4: Maximizing Parallel Downloads in the Carpool Lane by Tenni Theurer and Steve Souders. Published 2007.04.11 by Yahoo at yuiblog.com/blog/2007/04/11/performance-research-part-4. Accessed 2012.01.13.
Web Performance Best Practices. Published by Google at code.google.com/speed/page-speed/docs/rules_intro.html. Accessed 2012.01.13.
Website Performance: Taxonomy of Tips by Warren Gaebel. Published 2011.12.29 by Monitis at blog.mon.itor.us/2011/12/website-performance-taxonomy-of-tips. Accessed 2012.01.13.
Why Loading Third Party Scripts Async is Not Good Enough by Aaron Peters. Published 2011.11.23 by Aaron Peters at AaronPeters.nl/blog/why-loading-third-party-scripts-async-is-not-good-enough. Accessed 2012.01.13.
Try Monitis For Free. A 15-day free trial. Your opportunity to see how easy it is to use the Monitis cloud-based monitoring system. Credit card not required. Accessed 2012.01.13.
The Monitis Exchange at GitHub. This is the official repository for scripts, plugins, and SDKs that make it a breeze to use the Monitis system to its full potential. Accessed 2012.01.13.