How tracking scripts affect page loads… can tracking scripts kill my web app?

This post explains script blocking, and then shows how to safely setup a tracking script or any external script, such as Google Analytics or Quantcast, to not block page loads or other javascript handlers on your site.

The basics of scripts and blocking

  • HTML content that appears after a <script> tag will not display until the script is done downloading, parsing, and executing (blocking example)
  • Many javascript apps wait for the DOMContentLoaded event or an equivalent document ready event to apply functionality to the page
  • <script> tags prevent the document ready event from happening until they are done downloading, parsing, and executing
If these points make sense, skip forward to tracking scripts.

Script tags block

When a browser renders a web page it reads the HTML from top to bottom. When it encounters a <script> tag—maybe in the <head>, maybe in the <body>—it will halt from rendering the rest of the page, i.e. nothing else will show up, until the script has finished downloading, parsing, and executing.
Later scripts get blocked since a script can modify the page, add additional scripts, or add new variables to the window object. Some modern browsers will download multiple scripts in parallel (ie8, safari4) and future versions of browsers are expected to do this too, but, for the reasons just mentioned, scripts will still block the execution of later scripts and page content that is after a script will not be displayed until the script has finished.

Capturing the page load event

Many scripts need to wait for the page to load before they run, so they can do something simple like assigning event handlers to elements on the page or something more complex like paginating a long list (see jQuery UI or YUI). This can be done by assigning a function to run on window.load, but the window load event does not fire until the entire page has loaded—including images, flash, and applets. This means that users will be able to see and interact with the page, but not use your javascript enhancements until all the images have downloaded.
Mozilla and Opera fire a DOMContentLoaded event once the structure of the document has loaded and scripts have executed, but before the images, flash, and applets have loaded. By assigning a page load function to this event handler, all your javascript enhancements can be applied right when the page appears and often appear instantaneously to the user. It is important to realize that the DOMContentLoaded event will not fire until all scripts have downloaded and executed (more on this later).
Many javascript libraries offer a cross-browser way to attach a function to the equivalent of theDOMContentLoaded event. Here it is in jQuery and Prototype:
// jQuery
$(document).ready(function() { }) // or just $(function() { })

// Prototype
document.observe("dom:loaded", function() { });
Many developers rely heavily on these types of functions, especially for javascript/AJAX heavy web apps, and with this in mind, we can finally move on to the topic of tracking scripts.

Tracking Scripts

Tracking scripts are useful and extremely common. You can add as many of them as you want onto a web page. The most common tracking scripts are Google Analytics—which shows usage patterns to a site’s owner—and Quantcast—which can be used to broadcast how many people use your site and some characteristics about them. Another is Chartbeat—which emphasizes showing you analytics in real-time.
When you add a tracking script to your site, you are adding an additional script to your pages that will follow the same blocking rules as any script. This can be dangerous, because someone else’s server is hosting that script and if your servers are working fine, but something is wrong with their servers, it can affect page loads on your site.
Here is an example of the Google Analytics tracking script code. Notice there are 2 script blocks, the first adds the ga.js script to the page and downloads it (remember that the 2nd script is blocked from executing until this one has finished), and the second calls the tracker function with your tracking code.
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("_your_tracking_code_here_");
pageTracker._trackPageview();
} catch(err) {}
</script>
Tracking scripts are designed so you can download them once and have them cached safely in your browser for future page loads on your site and even better—for page loads on any other sites that use the same type of tracking scripts. Listed below are different ways to configure a tracking script, some are good, some are bad, and some are downright ugly. Each case looks at what happens when the tracking script is not in your browser cache and takes a REALLY long to download.

Script in the <head>

A slow script here will prevent anything from appearing on your pages until the script has finished (BOOM Headshot!). Hopefully, you’ve at least put the <title> above the script, so that will appear in the browser.
Newsweek.com had Quantcast configured this way when this blog post was written.

Script at the top of the <body>

A slow script here will have the same affect as putting it in the <head>. No actual content of the page will appear until this script has finished.
Macworld.com, evite.com, and popsugar.com all had Quantcast configured this way when this post was written.

Script at the bottom of the <body>

This is the configuration recommended by tracking script providers.
A slow script here—right before you close the body tags—will allow all of the content of the page to successfully render, but any document ready or DOMContentLoaded event handlers will not fire until the script has finished. This can be fine if your site doesn’t rely heavily on javascript to modify content on the page or bring advanced functionality to page (e.g., this type of configuration is fine for this blog).
However, if your site is a javascript heavy webapp, the initial content of the page will have loaded, but none of your javascript handlers will work yet. This can be a terrible experience if the script download fails for your users who will get annoyed, leave, and never come back<flashlight>FORRREEEVVVEEER</flashlight> (please excuse my attempted Sandlot reference).
This exact problem happened to a major media site a few years ago when some problem at Google was causing the Google Analytics script to not load and their entire site would not function for a period of hours. In fact, at Hunch, we noticed just a few weeks ago that Quantcast was having some problems serving content for about an hour and half (otherwise they’ve been good).

Script inserted after a load event

This technique is designed for javascript heavy websites. The tracking script code is inserted dynamically onto the page after a load event. Here is some sample code using jQuery:
<script type="text/javascript">
  $(window).load(function() {
    var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    $.ajax({
        url: gaJsHost+'google-analytics.com/ga.js', type: 'get', dataType: 'script', cache: true,
        success:function() { try { _gat._getTracker("_your_tracking_code_here_")._trackPageview(); } catch(err) {} }
    });
  })
</script>
Some things to be aware about:
  • window.load is not triggered until all images have finished downloading—so be careful with this if you have large, slow-loading images on your site
  • the order in which functions are attached to events is not guaranteed to be the order in which they are executed—that’s why this is using window.load instead of document.ready
  • this doesn’t work in Safari 2 or older with the current jQuery (1.3.2)—the ajax success function doesn’t get called

Google Analytics asynchronous tracking code

When I was writing this post, Google released their Google Analytics asynchronous tracking code. It’s a pretty slick approach that creates a script object dynamically and sets the async attribute to true. To configure it, you pass commands as strings into an array, which allows actions to queue up until the script loads and then run immediately once the script has loaded (see the link for specifics).
In most up-to-date versions of browsers (firefox 3.6, chrome, and safari 4) and ie6+ this code does not block the DOMContentLoaded event (or html). However, this event does get blocked in firefox 3.5 and Opera. Regardless this is pretty awesome for google analytics, and I highly recommend using it over the regular approach. Unfortunately this approach requires work by the script provider, so we’ll see if other tracking scripts, widgets, etc. take this approach.UPDATE: KISSmetrics added asynchronous support—finding more cases will be left as an exercise for the interested reader.

Host the script yourself

I forgot to mention this in my original post, but some tracking script services let you host the javascript file yourself, e.g., KISSmetrics lets you do this (if you don’t want to use their asynchronous script). If you do this, then the only time the script will get served slowly is when your site is already being slow, which means you don’t have to worry about the main point of this post—preventing a tracking script from slowing down your page loads, when everything else is fast. I think this is a great move for a big site with lots of resources since it can afford to serve the content quickly and not worry about loading something from an external server.

Conclusion

Scripts block content from loading on a web page. Prevent potential poor page loads on your site by properly configuring your tracking scripts either at the bottom of the <body> or—if you’re running a javascript heavy web app—in a window.load handler. Even popular sites sometimes get this wrong.
A slight reality check, the likelihood of scripts from a company like Quantcast or Google not loading is extremely low, but the Internet is never 100% trustworthy, so it’s nice to have things setup properly for the inevitable moment when things break. Fortunately with Google, you can now use their Google Analytics asynchronous tracking code.
Also, related to scripts and blocking, I just saw this in a tweet from @rr: LABjs: Loading And Blocking JavaScript. Looks like a pretty cool idea for controlling non-blocking of scripts, click over to the documentation part to see how it works.
UPDATE: I added info about the google analytics asynchronous tracking code
UPDATE 2: Here’s an example of this happening on a real site. I was on my favorite subway directions website and it was being bogged down by an advertisement. The javascript for their ad widget was not getting served, which blocked the main content on the page from appearing for 3 minutes and 45 seconds! Click through to see the full size images.
Share on Google Plus

About Admin

Arun is a JAVA/J2EE developer and passionate about coding and managing technical team.
    Blogger Comment
    Facebook Comment

0 comments:

Post a Comment