Tuesday, October 11, 2011

How to write a good Javascript widget


Writing a Javascript widget is almost easy but I learnt at my expense that it may be tricky. So I wrote some simple rule that help to do the job well.

1 - keep in mind: progressive ehnancement
I already wrote about it, just a recap: write html semantically correct (your mark up MUST have sense even WITHOUT Javascript)
2 - do not use inline styling (use CSS)
When your script are about to create your widget, find the outermost element and give to it a specifical class. Then do not attach style directly to the DOM elements, instead use CSS.
In this way you can customize the style of your widget without touching a single line of Javascript.
3 - avoid FOUC
Usually you modify the DOM after it is loaded. That way you may see the page while change. This is called FOUC (flash of unstyled content). You can avoid this hiding the DOM nodes you are about to change (using CSS) and show after (using Javascript).
Just a suggestion: you can use a noscript tag to show what you have hidden before in case Javascript is not enabled.
4 - use a library
A library like jQuery helps a lot with the DOM manipulation, It helps to forget the differences between the browsers. You can find a thorough guide to make a plugin here.
5 - do not calculate size and position during the widget creation
You can't assume what part of your page will be displayed and when. So you can't calculate position and size of elements at creation time. An example: I used this spinner widget on my application (http://btburnett.com/spinner/example/example.html). The widget calculates the input dimension and adds a lot of on-line styling for the little arrows. But in my application display the widget inside an hidden tab and all the size calculation returns wrong results.

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
document.getElementsByTagName('head')[0].appendChild(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).
JSONP
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
document.getElementsByTagName('head')[0].appendChild(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 :-)