51

Google Analytics async code uses a very distinct design pattern for javascript code execution.

The code depends on a library and it doesn't know if the library has loaded or not. If the library didn't load yet it just queues all the commands into an Array object. When the library loads it just creates the _gaq object and executes all commands in the sequence it was included. It then overwrites the push function so future commands are executed right away.

The idea is to make the commands run very fast when they are queued. The code is only really evaluated later when the library is loaded.

They also load the library with a parameters async=true. This causes almost no impact on the actual page loading time.

The commands look just like the sync versions of it, but the first string is a function name and the next parameters are that function parameters. You can also push functions into this array and the functions will be executed in sequence as well with a null context. So if you need to do something synchronous with the library you can push a function to do this inside _gaq.

I think this is a very clever solution but I have never seen it before. Does anyone know the name of this design pattern or where it's used besides the Google Analytics tracking code?

4 Answers 4

50

I've referred to it as "asynchronous function queuing", but its not quite a catchy name, and certainly not the formal name of the design pattern.

What's interesting is that, though I hadn't seen this particular pattern used before, since Google adopted it for Google Analytics, its been adopted widely by different platforms looking to nab the asynchronous juice (Disqus comes to mind.)

This blog post is the most in-depth examination of the async Google Analytics syntax I've read, and includes a fairly detailed explanation of how the one can replicate the pattern:

From the blog post:

var GoogleAnalyticsQueue = function () {

    this.push = function () {
        for (var i = 0; i < arguments.length; i++) try {
            if (typeof arguments[i] === "function") arguments[i]();
            else {
                // get tracker function from arguments[i][0]
                // get tracker function arguments from arguments[i].slice(1)
                // call it!  trackers[arguments[i][0]].apply(trackers, arguments[i].slice(1));
            }
        } catch (e) {}
    }

    // more code here…
};

// get the existing _gaq array
var _old_gaq = window._gaq;

// create a new _gaq object
window._gaq = new GoogleAnalyticsQueue();

// execute all of the queued up events - apply() turns the array entries into individual arguments
window._gaq.push.apply(window._gaq, _old_gaq);

It also notes that, even though not many browsers support the async attribute, the method of injection used makes the script load asynchronously in most browsers, and includes a helpful chart:

enter image description here

3

All it's doing is pushing data into a global array

var _qaq = _qaq || [];
_qaq.push(stuff);

It basically allows you to buffer up data to deal with before the library has loaded.

The main reason this pattern isn't used much is that other libraries generally need the resources to load before they can do anything. It wouldn't make any sense to start buffering jQuery commands.

It's not a pattern it's simply storing data in global scope and saying it's some-one elses job to process this, I don't care when you process it.

However it is a clever way to deal with the fact you don't know when something is loaded or ready, the common alternative is a DOMReady block.

6
  • 1
    If you want to use async=true in jquery.js file to reduce page loading time than there's no way to know if it finished loading or not when your code runs. Wouldn't it be nice to queue jQuery commands like this or maybe put all your code into a single function and queue it to be executed once jQuery finishes to load?
    – Eduardo
    Commented Aug 6, 2011 at 0:06
  • @eduardocereto sure it would. Suggest to jQuery that they should supply a global _domReady array they can read dom ready functions from.
    – Raynos
    Commented Aug 6, 2011 at 0:07
  • 1
    it's not a _domReady, it would be more like _jQueryReady, since the dom is not necessarily Ready. With the async=true flag the file may load before the DOM is ready or after the DOM is ready. The js file may load even after window.onload fires.
    – Eduardo
    Commented Aug 6, 2011 at 0:11
  • @eduardocereto do you have any backup on whether onload can fire before async scripts have loaded and executed
    – Raynos
    Commented Aug 6, 2011 at 0:16
  • 1
    async jQuery would definitely be an interesting project, but the problem is, you don't really want to delay it for too long, since if your jQuery triggers DOM modifications, those could come much later than you'd like, causing unslightly post-load modifications.
    – Yahel
    Commented Aug 6, 2011 at 0:19
3

A good writeup of javascript loading stratgies is available here http://friendlybit.com/js/lazy-loading-asyncronous-javascript/

And as far as I recall, ga.js async syntax has been inspired by Steve Souders. You can look at ControlJS , one of his projects

2
  • 2
    It deals with the actual script invocation and how not to delay the onload event. I'm more interested in here in how the queue the function calls into a simple array. That's the actual design I wanted to find similars.
    – Eduardo
    Commented Aug 9, 2011 at 1:27
  • Steve directly calls out in his posts the Google analytics loaders were the result of his work with them. You're spot on.
    – vhs
    Commented Jun 15, 2017 at 15:06
1

In 2014 Ilya Grigorik wrote a post titled Script-injected "async scripts" considered harmful. That post links to this question and uses the phrase "asynchronous function queuing" as the name of the design pattern used by Google Analytics.

Async function queuing differs from more recent design patterns like Fetch Injection, which don't require or need a globally defined queue. Here's an example of Fetch Injection implemented in the Fetch Inject module and used to asynchronously download resources in a document:

enter image description here

Notice the Fetch Injection design pattern is capable of loading CSS in addition to JavaScript in parallel, eliminating the blocking behavior of CSSOM and the Web Font download, greatly reducing perceived latency. Script execution order is fully preserved using an easy-to-understand API, making it simple to manage loading complex groups of resources with total programmatic control.

Not the answer you're looking for? Browse other questions tagged or ask your own question.