Tuesday, October 11, 2011

Javascript script injection

Javascript script injection is a tecnique that has two main uses. You can use to load and execute a script in asynchronous way and to build a sort of ajax call without using the xmlhttprequest object.
How the browser work
Before showing how this tecnique works, let me explain how the javascript is loaded and executed in the browser.
The main concept is that there is multiple threads for downloading the resources (a limited number for every subdomain) but only one thread of execution renders the page and execute the javascript code.
The first thing a browser does when loading a page is starts to parse the page and create the DOM tree. When it meet an inline script this is executed right away (even if the DOM tree is not completely loaded). When the parser met an external resource, it stops and download them (mainly stylesheets, and external javascripts. Images are loaded asynchronously).
It's usually a good idea to put your script inside a function executed when the DOM is fully loaded, for example the onload event or jquery's ready event.
The external resources are executed as soon as they are loaded, in the order they appear in the page. Since the execution of code and page rendering use the same thread, during the scripts execution and  loading the page stops to render and become unresponsive.
Download scripts asynchronously
Javascript injections permits to load a script asynchronously and execute just after loaded. This technique use DOM manipulation to inject a script node in the DOM tree:
var script = document.createElement('script');
script.setAttribute('src', 'script.js');    // load the script
This technique has some limitation: if you use it to download more than one script the order execution is not guaranteed. Some browser execute the code in order, others execute the code as the download is finished.
There are many Javascript libraries trying to generalize this approach: give a look to YEPNOPE, LABJS, REQUIRE.JS (they use other techniques as well).
Another useful way to use this technique is to inject a call to a URL that respond with a JSONP.
var script = document.createElement('script');
script.setAttribute('src', url + '?callback=handler');
// load the script
function handler(data){
//do stuff with data
A JSONP is a JSON wrapped inside a function call. For example:
handler({...various data...});
The script tag execute the code (using our handler). This is a clever hack but it has some drawbacks:

  • the way the callback is defined pollutes the namespace (It must be a window attribute)
  • the data can be sended using GET method and urlencoded (a limited amount of data)
  • downloading a file this way triggers many "busy indicators": the various way the browser has to say "I'm not finished yet". Read something of Steve Souders to learn more ...

A more "appropriate" tecnique to make cross site ajax request is CORS (but is not yet widely used).
Not only Javascript
I read an interesting post of Stoyan Stefanov who investigates the injection of stylesheets .
To say the truth the browsers load dinamically every type of external resources ....  this is how the browser works ... and it's amazing :-)