Loading a JS file programmatically using XHR

A problem that comes up every once in a while when writing a website is: how do I load a JS file programmatically and execute something after it's loaded?
A reason why you might want to do this is that you don't want to load a big ass bloated framework jQuery just to show a date picker in a specific page or function of your website or AJAX application.

There are several ways to accomplish this, but in this article I want to show a solution that I don't see used very often: using XHR to load the JS file, and using eval to parse it.
This is a very simple solution, it can be made compatible with browsers as old as IE6 (and possibly older), and can load any type of JS file, from alert("Hello world") to jQuery.

You are free to copy, modify and use this code as you wish.

Code

Loading...
Parameters
  • url: the JS file to load
  • onDone (optional): a function to be executed when the JS is loaded. If left undefined, nothing will happen after the file is loaded.
  • onError(e) (optional): a function to be executed if an error occurs. The parameter e can be either an HTTP error code (such as 404) or an Exception (for instance if a cross domain request is blocked). If left undefined, errors will be ignored. onDone is not called after an error.

How to use it

Basic usage

Let's say I want to have a checkbox for smooth scrolling on the page. It would be a waste to load it when it's not used, so when smooth scrolling is turned on, we can call this:

loadJS('smoothscroll.js',function(){smoothScroll(window)});
Loading multiple files

Want parallax scrolling too? To load multiple files, we can nest loadJS calls using the onDone callbacks. CSS files can also be loaded by appending them to the document:

loadJS('smoothscroll.js',function(){
  loadJS('parallax.js',function(){
    var d=document.createElement("link");
    d.rel="stylesheet"; d.type="text/css"; d.href="parallax.css";
    document.body.appendChild(d);
  smoothScroll(window, parallax);
  });
});
Avoid multiple loads if possible

If a JS file is loaded after an event (for instance, pressing a button), it may be a good idea to not load the file again after the first time, to improve performance. Use flags for this.
This is not mandatory, as browser caching will prevent multiple loads, but it will improve performance because eval will only be called once

Example 1: A simple load button

When you press the button below, test.js will be loaded. It contains a simple Hello world.

Example 2: jQuery date picker

This website does not use jQuery and loads pages via AJAX (that means no page reloads). The date picker shown below is the jQuery UI datepicker plugin, and is only loaded when you open this article using the loadJS function shown in this article.

Adding support for old browsers

The code shown so far will work on all modern-ish browsers, more specifically, IE9+.
To get IE6+ compatibility, we need to make a few changes:

  • IE6 does not use XMLHttpRequest, but ActiveXObject("Microsoft.XMLHTTP"): that's easy to solve, we just check if window.XMLHttpRequest is defined or not
  • .bind(this) is not supported by IE8-: Mozilla provides a handy polyfill for this, compatible with IE6+
  • IE6 can crash on nested XHRs: a simple workaround is to call the onDone function from outside the XHR context by using setTimeout with a delay of 1ms
New code
Loading...
That's little more than 1kb of code, less than 1kb when minified, and works on modern browsers as well.

Problem: same origin policy

The browser enforces same origin policy on XHR, therefore you can only load JS files from your domain.
If you need to load a JS file from another domain and you can't copy it to your domain, you cannot use this solution.
A way to get this done is to append a <script> element to the document and use setInterval to wait for a function to become defined, then you clear the timer and do whatever required that JS.
This method is used extensively on this site (even if I don't load anything external), but can only load JS files that define functions (such as libraries).

Download

Download code and examples
Both versions of loadAsync.js are included.

Share this article

Comments