Thursday, July 17, 2008

Ajax -loading javascript via AJAX

Ajax is the buzz word we are hearing around these days. Ajax is asynchronous javascript. Its the key ingradiant in making webapplications rich/ single page applications. What happens is that based on the events the user makes on the UI an asynchronous requests go to the server in the backend which does the processing and replies back. All this happens with out any page refresh/ with out stopping/pausing any of the user activities on the UI. We see this esp in creating a new logins in yahoo/ gmail -it reports name already exists/ strength of the password set.

The facility comes with a cost:
The main issue with ajax is: say you have one.html with one.js and two.html with two.js files. Say, two.html when opened in IE displays a calendar (using client side js). Now when the two.html is loaded in one.html by ajax the calendar will not be rendered!!! Mozilla gets the two.js but not loads them... IE does'nt even do this. The general way of handling such issues is by including the two.js in one.html along with one.js.

Yeak!!!! what a dirty solution! The Yeak... 'cos why should the parent one.html know the existince of two.js at all?? Moreover... say the two.js is not always required/ say we have multiple js files three.js and four.js (each of them very big) and the user either uses three.js or four.js but not both... then by the above apporach we would include all the js-s in one.html forcing the browser to load all of them before hand.... so the page not only loads un-necessary js files but also takes a lot of time to load/ render... this has severe issues w.r.t performace and user experiance. Now imagine a case where we display 10 ajax pages each with its own sets of javascript!!! Here we developed a similar application and the initial page loads 19 (5+5+4+5) javascript files which made the page response time: 10.25 seconds on an avg. There should be a better soln.

A Refined solution:
Let the initial page load only one.js and by on-demand loading (or lazy-loading) lets load the required js files. This we can do by DOM-modifications or loading js files by eval function. I found a useful link On-Demand Javascript.

Dom Modifications:
Here the HTML DOM is modified and a script tag is written to its bottom as:

by using

once the writing to dom is done it will get the required js file and load it. The point is that the user should keep in mind to delete such codes when no longer being used. Good one.

XMLHttpRequest-Based On-Demand Javascript
In this case the js file is called and the text part of it is eval()-ed. I understood it only to this extent. eval(): is a function in java script which can be used to create dynamic javascript behavior.
eg:
var alrt = 'alert("hi")';
eval(alrt);

in this case the string alrt is taken evaluated and loaded resulting into an alert of hi. This is the same as writing alert('hi');

Example:

I used YUI -loader to do all this donkey work for me. FInally the code became so simple and clean after using this... I am amazed !!!! Its as follows.




testLoad.html

DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

<link rel="stylesheet" type="text/css"

href="/yui/yui/assets/dpSyntaxHighlighter.css">

<script type="text/javascript" src="/yui/yui/build/yahoo/yahoo-debug.js">script>

<script type="text/javascript" src="/yui/yui/build/event/event-debug.js">script>

<script type="text/javascript" src="/yui/yui/build/dom/dom-debug.js">script>

<script type="text/javascript"

src="/yui/yui/build/yuiloader/yuiloader-beta-debug.js">script>

head>

<body id="yahoo-com" class=" yui-skin-sam">

<div id="custom-doc" class="yui-t2">

<div id="bd">

<div id="ajaxContainer">div>

div>

div>

body>

<script type="text/javascript" src="basic.js" >script>

html>




basic.js

Load = function(pageToLoad, whereToLoad) {

var childContainerCount = 0;

var scriptArr = new Array();

var isRemoteJsFile = false;

var loader = new YAHOO.util.YUILoader( {

require : [ 'connection' ],

base : [ '/yui/yui/build/' ],

onFailure : function(o) {

alert("error: " + YAHOO.lang.dump(o));

},

onSuccess :fire

});

loader.insert();

function lookupScript(text, index) {

scriptArr = text.toLowerCase().split(');

var js = scriptArr[index];

var jsEnd;

var jsStart;

jsStart = js.indexOf('src');

if (jsStart != -1) {

jsEnd = js.indexOf('.js');

// loading the js file

js = js.substring(jsStart + 3, jsEnd + 3);

js = js.replace('=', '');

js = js.replace('"', '');

//js = js.replace(/^\s\s*/, '').replace(/\s\s*$/, '');// trim

loadJs('yahooLang', '/yui/yui/build/yahoo/yahoo-min.js');

js = YAHOO.lang.trim(js);

} else {

// loading script body

jsStart = js.indexOf('>');

jsEnd = js.indexOf(');

js = js.substring(jsStart + 1, jsEnd);

}

return js;

}

var loadJs = function(name, jsPath, initFunc) {

loader = new YAHOO.util.YUILoader();

loader.addModule( {

name :name,

type :"js",

fullpath :jsPath,

varName :initFunc

});

loader.filter = {

'searchExp' :"-min\\.js",

'replaceStr' :"-debug.js"

};

loader.require(name);

loader.insert( {

onSuccess : function() {

if(initFunc != null && initFunc != undefined){

eval(initFunc + "()");

}

}

});

};

function fire() {

var parentDiv = document.getElementById(whereToLoad);

var childDiv = document.createElement('div');

childDiv.setAttribute('id', 'childContainer' + childContainerCount++);

if (!whereToLoad && whereToLoad != undefined)

parentDiv.appendChild(childDiv);

var handleSuccess = function(o) {

if (o.responseText !== undefined) {

scriptArr = o.responseText.toLowerCase().split(');

childDiv.innerHTML = o.responseText;

// loading each of the scripts of ajax file

for ( var i = 1; i <>

var js = lookupScript(o.responseText, i);

if (js.indexOf('.js') == -1) {

eval(js);

} else {

loadJs('ajaxJs' + i, js, 'initJs');

}

}

}

}

var handleFailure = function(o) {

if (o.responseText != undefined) {

alert('error');

}

};

var callback = {

success :handleSuccess,

failure :handleFailure,

argument : {

foo :"foo",

bar :"bar"

}

};

function makeRequest() {

var request = YAHOO.util.Connect.asyncRequest('POST', pageToLoad,

callback);

}

makeRequest();

}

};

Load('/yui/yui/examples/yuiloader/one.html', 'ajaxContainer');



This will load a html page which has an inline content and an included external js file. Our aim is to be able to load them.

one.html

DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>

<HEAD>

<TITLE> New Document TITLE>

<script src="/yui/yui/examples/yuiloader/one.js" >

script>

<script>

alert('hi hi hi hi 4');

script>

HEAD>

<BODY>

<font color="#FF0000" > 22222222222222 font>

BODY>

HTML>



one.js

function initJs(){

alert ('inside 2');

}




No comments:

Post a Comment