0.2 #permalink deferred, asap.js, minimal.js, and loadJS

Toggle example guides Toggle HTML markup

With speed being a primary concern, we don't allow javascript execution to block page loading. It's entirely possible to do anything you're used to, but it could take a little more work. For example, you can't assume that you have access to jQuery in the head or at any point in the body of your page, so putting

<script type="text/javascript">$(window).onload(function(){//etc});</script>

in your head or something like

<script type="text/javascript">$('.clazz').hide();<script>

in your body will not work.

Instead, the deferred array, asap.js and minimal.js files, and loadJS function should help you to get around most of these issues.

deferred

deferred is a simple javascript array that you can add functions to, and the functions will be executed once jQuery and the rest of our environment is set up. It's defined right up at the top of head.inc:

<script type="text/javascript">
   var deferred = [];
</script>

There are two ways to add functions to the deferred array. The things added can be functions taking no arguments, so:

<script type="text/javascript">deferred.push(positionSelectors);</script>
<script type="text/javascript">deferred.push(function(){$(window).onload(function(){//etc});});</script>

or you can add an array where the first element is a string matching the name of the function, and the remaining elements are arguments to be passed to the function:

deferred.push(["loadJS","/v2/js/modules/tile.js"])
deferred.push(["gg.img.loadBg","hero","/img/banners/hero_nonprofits","jpg"])

asap.js and minimal.js

/v2/js/asap.js and /v2/js/minimal.js are the (only!) scripts that are run on every page on our site. asap.js is run (asynchronously) quite early in the head, and minimal.js is run once the page has loaded. asap.js contains functions that absolutely must be run early in the pageload, such as the Optimizely snippet (to remove the undesirable "flash"), and code to set the refcode and conversion code (to give us the best chance possible of tracking people if they navigate away quickly). This is also where deferred and the top-level gg object are defined, so that pages have access to these variables. Because these scripts are run on every pageload, we need to be really vigilant to make sure everything in there needs to be in there.

loadJS

This is a tiny function (see the documentation here) that allows us to load scripts sequentially and asynchronously. The function takes two arguments: the first is the source of the script to load, and the second is the callback function to execute once it's loaded. It's being used to load minimal.js, since it (currently) requires jQuery, so first we load jQuery, then load minimal.js in the callback.

loadJS("/v2/js/deps/jquery-1.12.2.min.js", function() {
   loadJS("/v2/js/minimal.js");
});

If you need to load a number of scripts that don't directly depend on each other, you can pass an array of scripts to loadJS. Note that each script is loaded asynchronously, so there is no gurantee of execution order. But this can be useful if your page relies on a number of 3rd party scripts (say in PE or an admin console) that do not directly rely on each other. The following example show loading 5 scripts, and then calling an init function. Although the 5 indicated scripts may load (and execute) in any order, the init function will not get called until after all scripts are loaded. Note that the init function passed as a separate argument to loadJS.

   loadJS([
      "/javascript/jquery-ui/1.11.1/jquery-ui.js",
      "/javascript/jquery/jquery.blockUI-2.6.6.js",
      "/javascript/jquery/jquery.form.js",
      "/v2/js/deps/jquery.tablesorter-v2.45.5.combined.min.js",
      "/v2/js/admin/checkentry/edit-batch.js"
   ],
   init);

Or, to do things with deferred:

deferred.push([
   "loadJS", [
      "/javascript/jquery-ui/1.11.1/jquery-ui.js",
      "/javascript/jquery/jquery.blockUI-2.6.6.js",
      "/javascript/jquery/jquery.form.js",
      "/v2/js/deps/jquery.tablesorter-v2.45.5.combined.min.js",
      "/v2/js/admin/checkentry/edit-batch.js"
   ],
   init
]);

If you need to include external javascript, you can include it in the head or in the foot_scripts apache variable using the async parameter:

<!--#set var="foot_scripts" value='
  <script src="/path/to/myScript.js" async></script>
'-->

Or you can load it with loadJS. But note that your statement will be processed before loadJS has been defined, so you'll want to wrap it in a function and pass that to deferred:

deferred.push(
    ["loadJS",'/path/to/myScript.js',function(){//optional callback here}];
);
Example
Markup:
Markup
Markup:
Source: styleguide/styleguide.less, line 47