load scripts asynchronously

A couple solutions for async loading:

//this function will work cross-browser for loading scripts asynchronously
function loadScript(src, callback)
{
  var s,
      r,
      t;
  r = false;
  s = document.createElement('script');
  s.type="text/javascript";
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  t = document.getElementsByTagName('script')[0];
  t.parentNode.insertBefore(s, t);
}

If you’ve already got jQuery on the page, just use:

$.getScript(url, successCallback)*

Additionally, it’s possible that your scripts are being loaded/executed before the document is done loading, meaning that you’d need to wait for document.ready before events can be bound to the elements.

It’s not possible to tell specifically what your issue is without seeing the code.

The simplest solution is to keep all of your scripts inline at the bottom of the page, that way they don’t block the loading of HTML content while they execute. It also avoids the issue of having to asynchronously load each required script.

If you have a particularly fancy interaction that isn’t always used that requires a larger script of some sort, it could be useful to avoid loading that particular script until it’s needed (lazy loading).

* scripts loaded with $.getScript will likely not be cached


For anyone who can use modern features such as the Promise object, the loadScript function has become significantly simpler:

function loadScript(src) {
    return new Promise(function (resolve, reject) {
        var s;
        s = document.createElement('script');
        s.src = src;
        s.onload = resolve;
        s.onerror = reject;
        document.head.appendChild(s);
    });
}

Be aware that this version no longer accepts a callback argument as the returned promise will handle callback. What previously would have been loadScript(src, callback) would now be loadScript(src).then(callback).

This has the added bonus of being able to detect and handle failures, for example one could call…

loadScript(cdnSource)
    .catch(loadScript.bind(null, localSource))
    .then(successCallback, failureCallback);

…and it would handle CDN outages gracefully.

Leave a Comment