如今web應用上,ajax技術是大行其道。
ajax框架層出不窮,prototype,dojo,jquery,mootools,dwr,buffalo,ext,yui,spry。。。
ajax框架的出現,在提升開發生產效率的同時,也讓不少同學不明其內在原理,僅僅成為了某些框架的使用者。
(對于產品生產是好事,對于技術追求是壞事)
本文不涉及任何ajax框架的使用,本文僅通過一個模擬需求,在不使用任何ajax框架的前提下,以demo演示的方式,
向大家介紹ajax的原理以及應用場景。
ajax全稱是:
Asynchronous JavaScript And XML。
其本意是,通過javascript技術(JavaScript),通過異步http請求方式(Asynchronous),得到XML文本內容(XML)之后,通過javascript技術局部刷新web頁面內容。
從廣義的概念看,只要符合“異步請求,局部刷新web頁面”的技術,都可以成為ajax。
未必一定要使用javascript,一般情況下,大多數client端腳本代碼都可以;返回內容也未必一定要是xml,目前json格式,更為流行。
如何異步請求內容呢?
以javascript代碼作演示,如下:
function xmlhttpPost(url,func) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('POST', url, true);
self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
func(self.xmlHttpReq.responseText);
}
}
self.xmlHttpReq.send(null);
}
參數一,url:表明異步請求的資源地址
參數二,func:表明請求結束后,采用什么函數對請求結果內容進行回調處理
其實,這一個js代碼,就詮釋了ajax的全部含義--異步請求資源,將得到的資源內容,使用指定的function進行處理。
所以,ajax很簡單,大家千萬別被如今層出不窮的ajax框架給嚇怕了。要了解ajax的原理,就只要參看這段代碼即可。
如今的一些框架,僅僅在此基礎上,是封裝了一些公用的函數,方便開發人員調用。(當然,說說簡單,其實所謂的這些函數,大大方便了開發人員使用ajax技術。具體請參看ajax framework的官方介紹。)
特別說明:這個xmlhttpost方法改進了
simple-ajax。在原基礎上,將回調方法作為參數傳遞。
解釋了原理性的內容之后,接下來,以一個模擬的應用場景,demo說明ajax的使用,以及它的主要應用場景。
模擬場景:
目錄選擇,即當選擇一個目錄的時候,需要顯示這個目錄下的所有子目錄。
首先,我們來虛擬一個目錄結構,如下:
那么,要實現目錄選擇,有三個方式:
1)頁面初始化的時候,服務端將所有的目錄信息都put到頁面中。
優點:選擇操作簡單,有了全部的目錄信息,做選擇操作,都可以使用js完成,無需和服務端進行交互
缺點:當目錄信息很大的時候,比如有上萬個節點,整個目錄信息有1m左右大小,那么要渲染這個頁面,估計得20秒左右(視網速)
并且,很可能用戶僅僅只要選擇有限的幾個節點就可以,比如上萬個節點中選擇6-7個節點,那么浪費太大了;
2)頁面初始化的時候,服務端將當前需要的節點信息put到頁面上,一旦有選擇操作,重新刷新頁面。
優點:選擇操作簡單,對于節點信息,每次取需要的內容,不存在浪費現象
缺點:每次都要刷新整個頁面,除節點信息外,其他不變的東西都需要重新從服務端取,增加無謂的消耗。
3)頁面初始化的時候,服務端將當前需要的節點信息put到頁面上,一旦有選擇操作,只刷新節點相關的內容;
優點:每次只load需要的信息,局部刷新頁面內容,不存在任何浪費現象
缺點:需要異步請求數據,每次請求都需要和服務器交互,選擇操作稍顯復雜(異步請求,局部刷新)
通過這三種方式做對比,發現ajax主要適用的場景如下:
1)整體內容量大(幾百k,幾m,甚至幾十m),而頁面只需要其中一小部分信息即可;
2)數據顯示,只涉及一個頁面中部分數據信息的變動;
特別說明:至于使用ajax性能如何,需要對1,3兩個情況做性能測試,權衡使用。
針對第三種方案,
首先需要一個取節點資源的url,
演示代碼中,為了演示方便,使用php語言,而非使用主要語言java;
tree_node.php
<?php
$id = $_GET['id'];
if("1" == $id) {
echo("{\"id\":1,\"parentId\":-1,\"name\":\"1-1\",\"children\":[{\"id\":2,\"name\":\"2-1\"},{\"id\":3,\"name\":\"2-2\"},{\"id\":4,\"name\":\"2-3\"}]}");
} else if("2" == $id) {
echo("{\"id\":2,\"parentId\":1,\"name\":\"2-1\",\"children\":[]}");
} else if("3" == $id) {
echo("{\"id\":3,\"parentId\":1,\"name\":\"2-2\",\"children\":[]}");
} else if("4" == $id) {
echo("{\"id\":4,\"parentId\":1,\"name\":\"2-3\",\"children\":[{\"id\":5,\"name\":\"3-1\"},{\"id\":6,\"name\":\"3-2\"}]}");
} else if("5" == $id) {
echo("{\"id\":5,\"parentId\":4,\"name\":\"3-1\",\"children\":[]}");
} else if("6" == $id) {
echo("{\"id\":6,\"parentId\":4,\"name\":\"3-2\",\"children\":[{\"id\":7,\"name\":\"4-1\"}]}");
} else if("7" == $id) {
echo("{\"id\":7,\"parentId\":6,\"name\":\"4-1\",\"children\":[]}");
} else {
echo("");
}
?>
該文件中,寫死了目錄結構(一般情況下,往往根據樹對象,動態取得需要的節點)。
通過js,動態請求節點信息,部分刷新頁面內容:
<script type="text/javascript">
//模擬需求js
var nodeSelect = function(text) {
var tree = toJsonObje(text);
var options = document.getElementById("tree").options;
options.length = 0;
options.add(new Option("請選擇","-1"));
if(tree == null) {
return;
} else {
var children = tree.children;
for(i = 0; i < children.length; i++) {
var child = children[i];
options.add(new Option(child.name,child.id));
}
if(tree.parentId != "-1") {
options.add(new Option("上一級",tree.parentId));
}
}
document.getElementById("l").innerHTML = "當前位置:" + tree.name;
}
function nodeSelectAjax(id) {
var TREE_NODE_URL = "tree_node.php";
var url = TREE_NODE_URL + "?id=" + id;
xmlhttpPost(url,nodeSelect);
}
</script>
nodeSelectAjax,異步請求節點資源
nodeSelect,回調函數,根據請求信息,局部刷新頁面
至于請求資源信息格式,任何方式都可以,只要client端能解析就行。
目前json格式,比較流行。
最后,附上java使用json庫,生成json格式的方法:
JSONObject node = new JSONObject();
node.put("id", 1);
node.put("parentId", -1);
node.put("name", "1-1");
JSONArray children = new JSONArray();
JSONObject c1 = new JSONObject();
c1.put("id", 2);
c1.put("name", "2-1");
JSONObject c2 = new JSONObject();
c2.put("id", 3);
c2.put("name", "2-2");
children.put(c1);
children.put(c2);
node.put("children", children);
System.out.println(node.toString());
ajax demo
工程文件編碼:utf-8
工程運行:http server with php supported
ubuntu firefox下測試通過
其他:
不知道是不是ie的bug,居然不支持 select.innerHTML = value的方式
只能通過select.options.add(new Option("content","value") 動態往select中添加選項。