(Article) JavaScript - A Technique for Lazy Script Loading
Article : JavaScript - A Technique for Lazy Script Loading
A nice article from AJAXIAN that describes the javascript "lazy script loading" clearly.Bob Matsuoka has written a guest article on the topic of lazy script loading. Thanks so much Bob!
A recent article "Lazily load functionality via Unobtrusive Scripts" discussed how to lazily load Javascript script files by appending script elements to the HEAD tag. While this works as expected, I've found that for best results, you should also consider tracking which scripts have been loaded in order to prevent re-loading an already loaded script, and more importantly supporting callbacks so that you can guarantee loading of scripts prior to calling functions that depend on that code.
-
JAVASCRIPT:
/**
* Script lazy loader 0.5
* Copyright (c) 2008 Bob Matsuoka
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/
var LazyLoader = {}; //namespace
LazyLoader.timer = {}; // contains timers for scripts
LazyLoader.scripts = []; // contains called script references
LazyLoader.load = function(url, callback) {
// handle object or path
var classname = null;
var properties = null;
try {
// make sure we only load once
if ($A(LazyLoader.scripts).indexOf(url) == -1) {
// note that we loaded already
LazyLoader.scripts.push(url);
var script = document.createElement("script");
script.src = url;
script.type = "text/javascript";
$$("head")[0].appendChild(script); // add script tag to head element
// was a callback requested
if (callback) {
// test for onreadystatechange to trigger callback
script.onreadystatechange = function () {
if (script.readyState == 'loaded' script.readyState == 'complete') {
callback();
}
}
// test for onload to trigger callback
script.onload = function () {
callback();
return;
}
// safari doesn't support either onload or readystate, create a timer
// only way to do this in safari
if ((Prototype.Browser.WebKit && !navigator.userAgent.match(/Version\/3/)) Prototype.Browser.Opera) { // sniff
LazyLoader.timer[url] = setInterval(function() {
if (/loadedcomplete/.test(document.readyState)) {
clearInterval(LazyLoader.timer[url]);
callback(); // call the callback handler
}
}, 10);
}
}
} else {
if (callback) { callback(); }
}
} catch (e) {
alert(e);
}
}
Download the full source and example project.
Tracking Loaded Scripts
A common use of a lazy loader is in conjunction with "require" type function that allows you to specify which scripts are needed for a particular script to execute. Since library scripts are often called by more than one script, I thought it important to allow my lazy loader to track which scripts have already been loaded on a page to prevent unnecessary re-loading.
In this example, I've created the LazyLoader.scripts array. As each script is called, this script src is tested against the array of scripts already called, and if it exists, the script is not re-loaded, but its callback is executed. This allows you to call any required script as often as needed with impunity.
Supporting Callbacks
A more important addition is support for callbacks. It is my experience that with anything more than the simplest scripts, you cannot guarantee that a script is available for use unless it is called as part of a callback tied to the loading process. Unfortunately most of the browsers handle script onload events slightly differently. The examples I've provided should work for Firefox, Safari, and IE.
The basic logic for supporting callbacks is to allow a closure to be passed to the lazy loader. The function is then bound to the script event triggered by its loading. FF and Safari 3 support the "onload" event. IE supports the onreadystatechange event, and requires further testing of the state for either 'loaded' or 'complete' (depending on whether the script is cached).
Supporting callbacks in Safari 2 and Opera require a slight wrinkle, since neither support "onload" or "onreadystatechange" script events. For these browsers, you need to set a quick interval script to test document.readyState for "loaded" or "complete". Once ready, the interval can be cleared and the callback executed (I use a different interval for each script loaded, but I'm not sure that's necessary, since we are only testing the document object, not the state of the individual scripts).
Calling The Loader
Calling the loader is straightforward. This implementation is setup as a static function using a namespace. Here is an example without a callback:
-
JAVASCRIPT:
LazyLoader.load('js/myscript1.js');
Here is an example with a callback: -
JAVASCRIPT:
LazyLoader.load('js/myscript2.js', function(){
var myobj = new MyObject('myobj');
});
In the second example, the "myobj" instance of MyObject is only created after js/myscript2.js is loaded. You can also daisychain loaders by including them in the callback function.
Courtesy:- J2eeblogs.blogspot.com
- guru's blog
- Login to post comments
