試作lazy load pattern
Thu, 28 Jun 2007 16:24:13 +0800ajax patterns網站介紹了非常多的ajax design patterns,其中lazy load pattern具有相當的重要性,可以讓應用程式視需要載入適當的javascript模組,減少第一次載入網頁的時間。
這裡嘗試結合xmlhttp/xmlhttprequest來實作lazy load pattern,要載入的模組最後會透過eval()函數來執行。
在開始做以前,先說一下幾個原則:
- 在網頁中執行javascript時,global object就是window物件。
- 盡量使用匿名函數來把功能載入,這樣可以避免變數名稱的衝突。
- 考慮到函數/物件之間的相依性來規劃javascript模組。
- 在載入模組的函數中實作簡單的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物件有幾個函數:
- addField:用來加入表單的欄位跟值
- constructor:用參數傳入action的網址
- send:送出表單
- 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。