試作lazy load pattern

 Thu, 28 Jun 2007 16:24:13 +0800

ajax patterns網站介紹了非常多的ajax design patterns,其中lazy load pattern具有相當的重要性,可以讓應用程式視需要載入適當的javascript模組,減少第一次載入網頁的時間。

這裡嘗試結合xmlhttp/xmlhttprequest來實作lazy load pattern,要載入的模組最後會透過eval()函數來執行。

在開始做以前,先說一下幾個原則:

  1. 在網頁中執行javascript時,global object就是window物件。
  2. 盡量使用匿名函數來把功能載入,這樣可以避免變數名稱的衝突。
  3. 考慮到函數/物件之間的相依性來規劃javascript模組。
  4. 在載入模組的函數中實作簡單的same site policy,稍微提高安全性。

根據以上的原則,我試作了一個簡單的模組載入功能(init.js),以及一個以ajax的方式送出post請求的物件,叫做ajaxform(base.js)。

接下來,就來嘗試吧...先做init.js:

try {
window.execScript("null");
} catch (e) {
window.execScript = function (statement) {
eval(statement, window);
}
}
function load(path) {
try {
if (path.indexOf(":") > -1) {
throw "ERROR: ':' in path is not allowed.";
// an implement of a simplest "same site" policy
}
var loader = xmlhttp();
loader.open("GET", path, false);
loader.send(null);
if (loader.status == 200) {
window.execScript(loader.responseText);
} else {
throw "ERROR: " + loader.status;
}
} 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;
}

接下來試作form.js(這裡偷懶了,從以前做過的東西改的):

(function () {
//-- start
window.ajaxform = function (_host) {
// Public Properties
this.xmlhttp = new xmlhttp();
this.result = "";
this.resultXml = "";
this.callback = new Function();
// Private Methods
this._createBoundary = function () {
var tmp = Math.random();
var thisDate = new Date();
tmp = Math.abs(tmp*thisDate.getTime());
tmp = "--------" + tmp + "--------";
return tmp;
};
this._createField = function (_field, _value) {
var tmp = "--" + this._boundary + this.CRLF;
tmp += "Content-Disposition: form-data; name="" + _field + """ + this.CRLF;
tmp += "Content-Transfer-Encoding: binary" + this.CRLF + this.CRLF;
tmp += _value + this.CRLF
tmp += "--" + this._boundary + "--" + this.CRLF + this.CRLF;
return tmp;
};
var formObj = this;
this.xmlhttp.onreadystatechange = function () {
if (formObj.xmlhttp.readyState == 4) {
if (formObj.xmlhttp.status == 200) {
formObj.result = formObj.xmlhttp.responseText;
formObj.resultXml = formObj.xmlhttp.responseXML;
(formObj.callback)();
}
else {
formObj.errCode = formObj.xmlhttp.status;
formObj.result = formObj.xmlhttp.responseText;
alert("Error in request!! HTTP RESPONSE STATUS: " + formObj.errCode);
}
}
};
// Private Properties
this._boundary = this._createBoundary();
this._host = _host;
this._fields = {};
this.CRLF = "rn";
// Public Methods
this.addField = function (_field, _value) {
this._fields[_field] = _value;
};
this.removeField = function (_field) {
if (this._fields[_field])
delete this._fields[_field];
};
this.emptyField = function () {
this._fields = {};
};
this.send = function () {
this.xmlhttp.open("POST", this._host);
var msgBody = "";
for (key in this._fields){
msgBody += this._createField(key, this._fields[key]);
}
this.xmlhttp.setRequestHeader("Content-Type","multipart/form-data; charset=BIG5; boundary="+this._boundary);
this.xmlhttp.setRequestHeader("Connection","Keep-Alive");
this.xmlhttp.setRequestHeader("Content-Length",msgBody.length);
this.xmlhttp.send(msgBody);
};
this.setCallback = function (obj) {
if (obj instanceof Function) {
this.callback = obj;
}
};
};
//-- end
})();

說明一下,ajaxform物件有幾個函數:

  1. addField:用來加入表單的欄位跟值
  2. constructor:用參數傳入action的網址
  3. send:送出表單
  4. setCallback:指定xmlhttp的callback函數(間接執行),可以直接傳一個匿名函數或是函數的參考給它

為了要測試,寫了一個簡單的php來檢驗傳進來的東西:

<?php
print_r($_POST);
?>

最後用一個簡單的網頁把這些組合起來測試:

<html>
<head>
</head>
<script language="javascript" src="init.js"></script>
<script language="javascript">
load("form.js");
</script>
<body>
<script>
function sendpost () {
try {
var form1 = new ajaxform("test74.php");
form1.addField("title","中庸-經一章");
form1.addField("field1","天命之謂性,率性之謂道,修道之謂教。道也者,不可須臾離也;可離,非道也。");
form1.addField("field2","是故君子戒慎乎其所不睹,恐懼乎其所不聞。莫見乎隱,莫顯乎微,故君子慎其獨也。");
form1.addField("field3","喜怒哀樂之未發,謂之中;發而皆中節,謂之和。");
form1.addField("field4","中也者,天下之大本也;和也者,天下之達道也。");
form1.addField("field5","致中和,天地位焉,萬物育焉。");
form1.setCallback(function(){alert(form1.result);delete form1;});
form1.send();
} catch (e) {alert(e);}
}
</script>
<input type="button" value="test" onclick="sendpost()">
</body>
</html>

執行的結果如下,按下「test」按鍵,然後透過ajax送出post request,再用alert秀出傳回來的response。

測試的連結:http://www.fillano.idv.tw/test74.html