It seems that using this technique causes a caching problem which can really slow things down while developing.
Here is the notorious script:
function load_script (url)
{
var x = new ActiveXObject("Msxml2.XMLHTTP");
x.open('GET', url, false); x.send('');
eval(x.responseText);
var s = x.responseText.split(/\n/);
var r = /^function\s*([a-z_]+)/i;
for (var i = 0; i < s.length; i++)
{
var m = r.exec(s[i]);
if (m != null)
{
window[m[1]] = eval(m[1]);
}
}
}
load_script("/_customscript/customscript1.js");
load_script("/_customscript/customscript2.js");
load_script("/_customscript/customscript3.js");
In my opinion loading scripts using XMLHTTP should be avoided! Why?
1. The eval() function is very slow and should only be used as a last resort i.e. if no other options are available.
2. RegExp is also known to be slow especially with large documents.
3. Using XMLHTTP synchronously hangs / blocks the entire page until each resource is fully loaded.
Here is a better choice. Why?
1. Caching can be avoided easily.
2. Works much faster.
3. Does not block the page natural loading order and does not wait for other resources to finish loading.
function ScriptLoader(func)
{
var loader = this;
/* if ScriptLoading > 0 then scripts are still loading */
loader.ScriptLoading = 0;
/* the script entity point e.g. OnCrmPageLoad */
loader.Init = func;
/*
url - script url
noc - include a nocache querystring parameter
*/
loader.Load = function(url,noc)
{
var script = document.createElement("SCRIPT");
script.src = url + (noc ? "?nocache=" + Math.random() : "");
script.onreadystatechange = function()
{
if (!(script.readyState == 'loaded' || script.readyState == 'complete'))
{
return;
}
/* if loader.ScriptLoading > 0 true else false */
if (--loader.ScriptLoading)
{
return;
}
/* finished loading (loader.ScriptLoading == 0) , call entry point */
loader.Init();
}
/* append the script to the head tag */
document.documentElement.childNodes[0].appendChild(script);
/* indicate that this script is loading */
loader.ScriptLoading++;
}
}
/*
create a Script loader object + function to be called when the script has
finished loading
*/
window.ScriptLibrary = new ScriptLoader(OnCrmPageLoad);
/* url , false - cache, true - no cache */
ScriptLibrary.Load('/ISV/SCLIB/JScript1.js',false);
ScriptLibrary.Load('/ISV/SCLIB/JScript2.js',true);
ScriptLibrary.Load('/ISV/SCLIB/JScript3.js',false);
/* Start Script Execution */
function OnCrmPageLoad()
{
var res = JS2Function();
res += "," + JS1Function();
res += "," + JS3Function();
alert(res)
}
The remote scripts functions can be written in such a way (e.g. window.FuncName = function(){ /* code */ }) which immediately exposes them to the window scope e.g.
// JScript3.js File
window.JS3Function = function()
{
return 'JS3Function';
}
// JScript2.js File
window.JS2Function = function()
{
return 'JS2Function';
}
// JScript1.js File
window.JS1Function = function()
{
return 'JS1Function';
}