兩種動態加載javascript的方法

 Tue, 10 Apr 2007 20:50:41 +0800

我自己是在改良網頁Isometric引擎時碰到這樣的需求(動態載入地圖),最早是用連到不同網頁避開這個問題,最近看到別人嘗試的一些方法,所以自己再試試看。

這些方法有:

  1. 利用document.createElement("script")來產生script node,並加到Node Tree中。
  2. 利用Ajax取得.js檔案內容,並透過eval函數來執行內容。

經過嘗試以後,大概有了一些心得。

以下是對第一個方法的測試

主要的script:

var nav = null;
function addScript(name) {
var obj = document.createElement("script");
obj.src = name;
var target = document.getElementsByTagName("HEAD")[0];
target.appendChild(obj);
}
function test (name) {
try {
addScript(name);
setTimeout("alert(nav.getInner())", 100);
} catch (e) {
alert(e);
}
}

要載入的test1.js檔案:

var nav = {
"inner": 0,
"getInner": function () { return this.inner; }
};
(這樣不是合法的JSON,不過還是可以執行)

測試的網頁內容:

<input type="button" value="test" onclick="test('test1.js')">
(上面是用全形的<>符號,避免顯示成按鈕)

有興趣可以測試一下:第一個測試網頁連結

這個方法有幾個問題:

  1. 在firefox改變不會立刻生效,所以我用setTimeout來延緩測試
  2. 需要對node做適當的管理,否則會佔用不必要的系統資源

接下來使用ajax + eval的方法。

主要的script:

var nav=null;
if (window.execScript == null) {
try {
window.execScript = function(script) {
eval(script,window);
}
} catch (e) { alert(e); }
}
function useScript (name) {
try {
var loader = xmlhttp();
loader.open('GET', name, false);
loader.send(null);
window.execScript(loader.responseText.toString());
} catch (e) {
alert(e);
}
}
function test1 (name) {
try {
useScript(name);
alert(nav.getInner());
} catch (e) {
alert(e);
}
}
function xmlhttp() 
{
try{return new ActiveXObject("Msxml2.XMLHTTP");} catch(e){}
try{return new ActiveXObject("Microsoft.XMLHTTP");} catch(e){}
try{return new XMLHttpRequest();} catch(e){}
alert("XMLHttpRequest Object not existed!!");
return null;
}

要載入的test2.js檔案:

nav = {
"inner": 3,
"getInner": function () { return this.inner; }
};

測試的網頁內容:

<input type="button" value="test" onclick="test1('test2.js')">
(上面是用全形的<>符號,避免顯示成按鈕)

有興趣可以測試一下:第二個測試網頁連結

有幾個部份需要說明一下:

  1. 在ie上,eval沒辦法取用到global variables,所以使用window.execScript來代替,並且為firefox的window物件加上這個函數,讓兩個瀏覽器可以用同樣的方法操作。execScript的第二個參數可以省略,因為預設就是JavaScript,我這裡就偷懶不寫了。
  2. eval所執行的程式,會參考到執行eval時程式的上下文,所以特別給定第二個參數為window物件,讓他可以取用global variable。