Question

I'm building a Google Analytics-esque platform which works with a pretty standard flow:

  1. Users get and configure a JS snippet with their unique account parameters.
  2. They embed this JS snippet on their website, which loads my main library asynchronously.
  3. After the library loads, users are able to call it's methods to send data to my web app.

After researching a few different implementations of how various companies handle the above flow, I found that Google's new Universal Analytics tag appears to have the most elegant execution for the following reason:

It seems to allow users to make method calls while the main library is still asynchronously loading, all within the one <script type="text/javascript"> tag.

An example of this is straight in the Quick Start Code:

<!-- Google Analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXX-Y', 'auto');
ga('send', 'pageview');

</script>
<!-- End Google Analytics -->

I'm trying to understand how it allows a user to call ga('create' ... ) and ga('send' ... ) while the main anonymous function is still presumably manipulating the DOM and inserting/downloading the analytics.js script.

Does anybody know how the above pattern works?

An attempt at reverse engineering their minified code seems to suggest that they may be creating a blank ga Object which effectively acts as a queue of messages until the main library loads. Then, when the library loads, it looks to be parsing the queue object and doing what it needs to do (since it will be able to actually perform its tasks given that the library has loaded).

I'm not 100% sure whether the above is correct, as it's a bit tricky to reverse engineer all their code.

I created a similar implementation in which I use a window.tempDataWhileLibraryHasntLoaded object to store all data called by methods like ga("send" ...) before the library has loaded.. the library then parses this object, processes what it needs to, and nulls the object, however this doesn't seem as clean as Google's implementation.

Was it helpful?

Solution

So unravelling the minified script, it looks like this (with the code for inserting the script tag removed):

window.GoogleAnalyticsObject = 'ga';

window.ga = window.ga || function(){
    ( window.ga.q = window.ga.q || [] ).push(arguments);
}

window.ga.l = 1 * new Date();

They create window.ga and assign it to a function which pushes any arguments into an array, window.ga.q. The || or operators are there to make sure things aren't overwritten if they've already been created.

So when you call ga('foo', 'bar') it simply stores those arguments in the array. When the script has loaded it will look for the window.ga.q array and loop through its values, finding 'foo' and 'bar' and calling the corresponding functions in the loaded script.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top