Pencarian

Rss Posts

 

 

 

JavaScript: Asynchronous Script Loading and Lazy Loading – Federico Cargnelutti

Jul 12, 2011

Most of the time remote scripts are included at the end of an html document, right before the closing body tag. This is because browsers are single threaded and when they encounter a script tag, they halt any other processes until they download and parse the script. By including scripts at the end, you allow the browser to download and render all page elements, style sheets and images without any unnecessary delay. Also, if the browser renders the page before executing any script, you know that all page elements are already available to retrieve.

However, websites like Facebook for example, use a more advanced technique. They include scripts dynamically via DOM methods. This technique, which I?ll briefly explain here, is known as ?Asynchronous Script Loading?.

Lets take a look at the script that Facebook uses to download its JS library:

(function () {
    var e = document.createElement('script');
    e.src = 'http://connect.facebook.net/en_US/all.js';
    e.async = true;
    document.getElementById('fb-root').appendChild(e);
}());

When you dynamically append a script to a page, the browser does not halt other processes, so it continues rendering page elements and downloading resources. The best place to put this code is right after the opening body tag. This allows Facebook initialization to happen in parallel with the initialization on the rest of the page.

Facebook also makes non-blocking loading of the script easy to use by providing the fbAsyncInit hook. If this global function is defined, it will be executed when the library is loaded.

window.fbAsyncInit = function () {
    FB.init({
        appId: 'YOUR APP ID',
        status: true,
        cookie: true,
        xfbml: true
    });
};

Once the library has loaded, Facebook checks the value of window.fbAsyncInit.hasRun and if it?s false it makes a call to the fbAsyncInit function:

if (window.fbAsyncInit && !window.fbAsyncInit.hasRun) {
    window.fbAsyncInit.hasRun = true;
    fbAsyncInit();
}

Now, what if you want to load multiple files asynchronously, or you need to include a small amount of code at page load and then download other scripts only when needed? Loading scripts on demand is called ?Lazy Loading?. There are many libraries that exist specifically for this purpose, however, you only need a few lines of JavaScript to do this.

Here is an example:

$L = function (c, d) {
    for (var b = c.length, e = b, f = function () {
            if (!(this.readyState
            		&& this.readyState !== "complete"
            		&& this.readyState !== "loaded")) {
                this.onload = this.onreadystatechange = null;
                --e || d()
            }
        }, g = document.getElementsByTagName("head")[0], i = function (h) {
            var a = document.createElement("script");
            a.async = true;
            a.src = h;
            a.onload = a.onreadystatechange = f;
            g.appendChild(a)
        }; b;) i(c[--b])
};

The best place to put this code is inside the head tag. You can then use the $L function to asynchronously load your scripts on demand. $L takes two arguments: an array (c) and a callback function (d).

var scripts = [];
scripts[0] = 'http://www.google-analytics.com/ga.js';
scripts[1] = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js';

$L(scripts, function () {
    console.log("ga and jquery scripts loaded");
});

$L(['http://connect.facebook.net/en_US/all.js'], function () {
    console.log("facebook script loaded");
    window.fbAsyncInit.hasRun = true;
    FB.init({
        appId: 'YOUR APP ID',
        status: true,
        cookie: true,
        xfbml: true
    });
});

You can see this script in action here (right click -> view page source).


Filed under: Design Patterns, Programming, Software Architecture the original (another 826 bytes)

Javascript on the Desktop (well Linux Mostly) – Alan Knowles

Jan 19, 2010


Unfortunately my internet line died over the weekend, and I was left without a connection until Tuesday. I had a bit of offline time to have a look at some interesting new(ish) technology.

If you have paid any attention to Gnome development, there are mentions of gnome-shell, and something about making it easier to develop add-on/applets etc. using Javascript. I have not really had time to look at this much, however given the fact I had downloaded all the components prior to my loss of connectivity, I spent some time over the weekend and monday looking at this in more detail.

It looks like there are obviously things going on in IRC and mailing lists, so most of my impressions are from the websites, and code. There are basically 2 projects currently.

GJS – This is the mozilla Javascript engine bound to the gobject introspection system
Seed – This is the webkit Javascript engine bound to the gobject introspection system

Of the two, Seed apears to be a little more advanced and more time has gone into it, based on the fact there appear to be more core features in Seed (eg. I could not find anything like Seed.print() in GJS), and there are very few examples in GJS

Both of these use the GObject introspection method to bind to Gtk, and a large and growing number of other libraries. This is something I found very interesting having gone through a similar process with rooscript.

The fundimental issue of creating bindings to Gtk (and anything that uses the GObject system) is that historically, almost everyone (PHP, Python etc.) who did it used this method.

* Parse the html documentation, or the .h files (extracting the classes, enums, methods, arguments etc.)
* Generate Binding code for each library, which wraps these methods, loads the ‘.so’ libraries and links it all together.
* Compile a Module (or statically link it in some cases)
* Run… Test.. Fix bugs in wrapping code… Run … Test.

What GObject inspection introduces is an very thin layer that can be used to expose any of these methods without writing any binding code (other than to GObject inspection). The result is that to add more features (linking to another library) – you just have to generate a XML file describing the interface, compile it with g-ir-compile and put it in the right folder, and you have magically added support to a new Library, without generating an C code!

This also means that fixing the binding is considerably simpler (fix the XML file, re-compile etc.) and you have solved bugs in any language that is using it… (as I found with gtk_tree_store_set_column_types()


Playing with the languages.


GJS and Seed present the Gtk API very slightly differently, which at present appears to be a bit of a blocker for deciding which to use (or even to bother for some). The key differences are for authoring

* Javascript ‘let’ features in GJS – not available in Seed.. – This is rather a big blocker as code designed for GJS will fail in Seed totally.. (and visa-versa probably)
* Different call signatures to signalsÃ? Ã? Ã?  SEED:OBJECT.signal.connect(method)Ã?  vsÃ?  GJS:OBJECT.connect(’signal’, method)Ã?  – I think personally that GJS way is more true to the concept and cleaner, however as you can see below there are ways around this.

Seed has a git repo on gnome ’seed-examples’, which contains a large number of examples, although their depth is rather thin unfortunatly.. (code coverage is probably 1% at best)…
Both have pretty much Zero in the documentation stakes.. – A rather trivial task to create – which I’m tempted to have a go at….


Anyway back to my playing around..


I’ve been doing some serious shit in Javascript recently, GUI builders, Code generators, Hacking GTK bindings etc. so I’ve seen the good, bad and ugly as far as Javascript goes (Bad sometimes being my code).Ã?  I’ve been slowly moving to what I regard as an effecient, productive use of Javascript, most of which can be seen in the xtype support in RooJS

After runing the first few examples in seed-examples, I decided to see if using an xtype / Roo structure could be done with Seed. After a bit of tweaking, and bugfixing of Seed, I finally got this code to work.



var win = XN.xnew({
xtype : Gtk.Window,
type: Gtk.WindowType.TOPLEVEL,
listeners : {
'delete-event' : function (widget, event) {
return false;
},
destroy : function (widget) {
Gtk.main_quit();
}
},

set : {
set_border_width : [ 10 ],
resize : [300, 300],
show_all : []
},
items : [

Truncated by Planet PHP, read more at the original (another 5487 bytes)