The manner in which a page loads script can have a direct bearing on the perceived performance of the page... here are couple of optimization techniques to be mindful of when referencing script files within a page that cover the "how scripts are loaded" and "when scripts are loaded" aspects of the page:
Script tags vs. programmatic script loading
Often times developers simply add <script> tags directly in the page, either in the <head> section or usually somewhere toward the end of the document. Unfortunately this usage pattern results in sub-optimal behavior. The browser must start downloading the script when it encounters a <script> tag, wait for the HTTP request to complete, process the script and run it before it can parse any further. This is because the browser has to assume that script may contain document.write calls to actually create new HTML content that needs to be parsed before the content after the script is parsed. Document.write is a pretty poor practice given the richer DOM capabilities now available in browsers. It can easily be replaced by script that inserts HTML into a known location.
In Atlas we make the assumption that script files will not contain interspersed HTML content to enable the performance optimization. We still need at least one regular script tag to bring in the bootstrapping code itself. Once loaded, the bootstrapping code contains a script loader that will programmatically create script elements and download scripts in the background as the browser continues to parse the HTML content and render it sooner without waiting for scripts. In the current implementation, the list of script references are declared in an xml-script block, but that is just an implementation detail; the general idea is that programmatic loading of scripts results in faster page rendering, and improved perceived performance.
We've also had some thoughts around how to define dependencies across script files. Admittedly, it starts to get a little complex (hence we haven't done it just yet)... but once that information is available, its possible to load more than one script file at a time. This becomes especially useful when larger, high-traffic sites can afford to set up multiple script domains, and are able to break out of the 2 connections per domain browser limits and truly parallelize script loading.
Loading scripts sooner than window.onload
When pages do adopt the programmatic script loading approach rather than individual script tags, they usually kick-start the download process by handling the window.onload event. This is also what Atlas does by default. For most pages this works fine. However, you may have some pages that bring down multiple css files, or more likely multiple images. The window.onload event is raised when all the linked content is downloaded... and can in fact happen much later than when the document itself has been parsed, the DOM tree has been built up and is ready to be scripted. During this interim, the page is in sort of an indeterminate state, which could make it feel slow. Even worse, the user may start interacting with the rendered page immediately, and may find the page does not function as expected!
The solution to this is simply to start loading the scripts sooner. A good location to kick-start script loading is simply when the browser has completed parsing any content on the page. This way the DOM can be safely accessed from the script, and at the same time, the script doesn't need to wait for things like images to download before it gets to start doing its thing. This is a very simple solution that works well across browsers, and it turns out, Atlas supports this for those who'd like to take this extra step.
Here is what happens under the covers: The key part of the bootstrapper in Atlas is the Sys.Runtime class. It registers for the window.onload event among other things and in turn surfaces its own load event. The Sys.Application class registers for this load event on Sys.Runtime, and starts downloading referenced scripts in response to that event. As a result, by default, scripts are loaded in response to window.onload.
However the Sys.Runtime class also exposes an initialize() method (which is in fact called by the window.onload event handler)... this can be used by the page developer as well to programmatically kick-start the process. Essentially this causes the Sys.Runtime class to stop waiting for window.onload and go ahead with raising its load event right then and there. Calling initialize() repeatedly or after window.onload is simply a no-op. It is quite simple to apply this technique... simply add this little bit of script to the end of your page, for example after the <body> tag:
<script type="text/javascript">
Sys.Runtime.initialize();
</script>
What do you think of this technique?
This is just scratching the surface in terms of the variety of techniques. There are obviously other techniques in the quest to optimize the script loading behavior including compressing scripts, combining multiple scripts etc. etc. You might want to check out my JavaScript Utilities project for some basic tools to help with these. Care to share any tricks that you think could be successfully applied in a general manner?
Posted on Saturday, 8/26/2006 @ 3:17 PM
| #
ASP.NET