Ajax 能夠做什嗎?
如今 Google Suggest 和 Google Maps 使用了 Ajax,通過 Ajax,我們可以使得用戶端得到豐富的應用體驗及交換操作,而使用者不會感覺到有網頁提交或重新整理的過程,頁面也不需要被重新載入,應用的資料交換都被隱藏。
傳統的 WEB 應用程式模型是這樣工作的:使用者的介面操作觸發 HTTP 要求,伺服器在接收到請求之後進行一些商務邏輯處理,如儲存資料等,然後向用戶端返回一個 HTML 頁面。但這種方式並沒有給予使用者很好的應用體驗,當伺服器在處理資料的時候,使用者則處於等待的狀態,每一步操作都需要等待,太多的等待會使使用者越來越沒有耐心。而 Ajax 則大不相同,它通過 Ajax 引擎,使得應用過程很自然,操作很流暢,因為其只和伺服器交換有用的資料,而頁面顯示等不必要的資料則不再重新載入。Ajax 引擎其實就是 JavaScript、XML、XMLHttpRequest 等等各項技術的綜合應用。
為什麼使用AJAX?
1、通過適當的Ajax應用達到更好的使用者體驗;
2、把以前的一些伺服器負擔的工作轉嫁到用戶端,利於用戶端閑置的處理能力來處理,減輕伺服器和頻寬的負擔,從而達到節約ISP的空間及頻寬租用成本的目的。
AJAX從哪裡來的?
Ajax這個概念的最早提出者Jesse James Garrett認為:
Ajax是Asynchronous JavaScript and XML的縮寫。
Ajax並不是一門新的語言或技術,它實際上是幾項技術按一定的方式組合在一在同共的協作中發揮各自的作用,它包括:
- 使用XHTML和CSS標準化呈現;
- 使用DOM實現動態顯示和互動;
- 使用XML和XSLT進行資料交換與處理;
- 使用XMLHttpRequest進行非同步資料讀取;
- 最後用JavaScript綁定和處理所有資料;
Ajax的工作原理相當於在使用者和伺服器之間加了—個中介層,使使用者操作與伺服器響應非同步化。並不是所有的使用者請求都提交給伺服器,像—些資料驗證和資料處理等都交給Ajax引擎自己來做,只有確定需要從伺服器讀取新資料時再由Ajax引擎代為向伺服器提交請求。
AJAX的核心技術有哪些?
雖然Garrent列出了7條Ajax的構成技術,但個人認為,所謂的Ajax其核心只有JavaScript、XMLHTTPRequest和DOM,如果所用資料格式為XML的話,還可以再加上XML這一項(Ajax從伺服器端返回的資料可以是XML格式,也可以是文本等其他格式)。
在舊的互動方式中,由使用者觸發一個HTTP請求到伺服器,伺服器對其進行處理後再返回一個新的HTHL頁到用戶端,每當伺服器處理用戶端提交的請求時,客戶都只能空閑等待,並且哪怕只是一次很小的互動、只需從伺服器端得到很簡單的一個資料,都要返回一個完整的HTML頁,而使用者每次都要浪費時間和頻寬去重新讀取整個頁面。
而使用Ajax後使用者從感覺上幾乎所有的操作都會很快響應沒有頁面重載(白屏)的等待。
XMLHttpRequest簡稱 XmlHttp
它是一套可以在Javascript、VbScript、Jscript等指令碼語言中通過http協議傳送或從接收XML及其他資料的一套API。XmlHttp最大的用處是可以更新網頁的部分內容而不需要重新整理整個頁面。
來自MSDN的解釋:XmlHttp提供用戶端同http伺服器通訊的協議。用戶端可以通過XmlHttp對象(MSXML2.XMLHTTP.3.0)向http伺服器發送請求並使用微軟XML文件物件模型Microsoft XML Document Object Model (DOM)處理回應。
現在的絕對多數瀏覽器都增加了對XmlHttp的支援,IE中使用ActiveXObject方式建立XmlHttp對象,其他瀏覽器如:Firefox、Opera等通過window.XMLHttpRequest來建立xmlhttp對象。
屬性:
| onreadystatechange* |
指定當readyState屬性改變時的事件處理控制代碼。唯寫 |
| readyState |
返回當前請求的狀態,唯讀. |
| responseBody |
將回應資訊本文以unsigned byte數組形式返回.唯讀 |
| responseStream |
以Ado Stream對象的形式返迴響應資訊。唯讀 |
| responseText |
將響應資訊作為字串返回.唯讀 |
| responseXML |
將響應資訊格式化為Xml Document對象並返回,唯讀 |
| status |
返回當前請求的http狀態代碼.唯讀 |
| statusText |
返回當前請求的響應行狀態,唯讀 |
著重介紹下readyState屬性
返回XMLHTTP請求的目前狀態,每個數值代表一個狀態
| 0 (未初始化) |
對象已建立,但是尚未初始化(尚未調用open方法) |
| 1 (初始化) |
對象已建立,尚未調用send方法 |
| 2 (發送資料) |
send方法已調用,但是當前的狀態及http頭未知 |
| 3 (資料傳送中) |
已接收部分資料,因為響應及http頭不全,這時通過responseBody和responseText擷取部分資料會出現錯誤, |
| 4 (完成) |
資料接收完畢,此時可以通過通過responseBody和responseText擷取完整的回應資料 |
方法:
| abort |
取消當前請求 |
| getAllResponseHeaders |
擷取響應的所有http頭 |
| getResponseHeader |
從響應資訊中擷取指定的http頭 |
| open |
建立一個新的http請求,並指定此請求的方法、URL以及驗證資訊(使用者名稱/密碼) |
| send |
發送請求到http伺服器並接收回應 |
| setRequestHeader |
單獨指定請求的某個http頭 |
如何正確使用Ajax?
這裡我們拿一個項目中常用的使用者註冊校正是否有重複使用者名稱存在的案例來示範。並分別用get方式回傳json,post方式回傳json,post方式回傳xml來示範。
首先我們得考慮在不同瀏覽器下如何獲得XmlHttp對象
function creatXmlHttpRequest() {if (typeof XMLHttpRequest != 'undefined'){return new XMLHttpRequest();}else if (typeof ActiveXObject != 'undefined'){var MSXML = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0','MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP','Microsoft.XMLHTTP'];for (var i = 0; MSXML.length; i ++){try{return new ActiveXObject(version[i]);}catch (e){//.......}}}else{throw new Error('您的系統或瀏覽器不支援XHR對象!');}}
GET方式回傳json
function checkUserByAjaxGet() {// 第一步,得到一個XMLHttpRequest對象// var xhr=new XMLHttpRequest();// 如果說IE6,就需要使用Active組建// xmlhttp=new ActiveXObject(MSXML[n]);var xhr = creatXmlHttpRequest();var name = document.rgform.username.value;// 設定一個事件的監聽函數xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if (xhr.status == 200 || xhr.status == 304) {var ret = xhr.responseText;var _ret = eval('(' + ret + ')'); //var _ret = JSON.parse(ret);document.getElementById("msg").innerHTML = _ret.tip;if (_ret.success = true) {document.rgform.username.focus();}}}}// 第二步,準備一個串連請求xhr.open("get", "checkuserByJSON.jsp?name=" + name, true);// 第三步,發起請求xhr.send(null);}
POST方式回傳json
function checkUserByAjaxPost() {// 第一步,建立xhr對象var xhr = creatXmlHttpRequest();var name = document.rgform.username.value;// 第二步,設定一個事件的監聽函數xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if (xhr.status == 200 || xhr.status == 304) {var ret = xhr.responseText;var _ret = eval('(' + ret + ')'); //var _ret = JSON.parse(ret);document.getElementById("msg").innerHTML = _ret.tip;if (_ret.success = true) {document.rgform.username.focus();alert(xhr.getResponseHeader("Content-Length"));alert(xhr.getResponseHeader("Content-Type"));alert(xhr.getResponseHeader("Date"));alert(xhr.getResponseHeader("Server"));}}}}// 第三步,準備一個POST串連請求xhr.open("post", "checkuserByJSON.jsp", true);// 使用post方式提交,必須要加上如下一行xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");// 第四步,發起請求xhr.send("name=" + name + "&password=ppppp");}
POST方式回傳xml
function checkUserByAjaxPostXml() {// 第一步,建立xhr對象var xhr = creatXmlHttpRequest();var name = document.rgform.username.value;// 第二步,設定一個事件的監聽函數xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if (xhr.status == 200 || xhr.status == 304) {var ret = xhr.responseXML;var successNode = ret.getElementsByTagName("success")[0];var tipNode = ret.getElementsByTagName("tip")[0];document.getElementById("msg").innerHTML = tipNode.firstChild.nodeValue;if (successNode.firstChild.nodeValue == true) {document.rgform.username.focus();}}}}// 第三步,準備一個POST串連請求xhr.open("post", "checkuserByXML.jsp", true);xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");// 第四步,發起請求xhr.send("name=" + name + "&password=ppppp");}
返回的的json
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%><%@ page import="java.util.*" %><%String username = request.getParameter("username");response.setContentType("application/json;charset=UTF-8");response.setHeader("pragma","no-cache");response.setHeader("cache-control","no-cache");if("admin".equals(username)){response.getWriter().write("{\"success\":"+true+",\"tip\":\"使用者名稱已存在\"}");}else{response.getWriter().write("{\"success\":"+false+",\"tip\":\"使用者名稱可以使用\"}");}%>
返回的xml
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%><%@ page import="java.util.*" %><%String userId = request.getParameter("name");response.setContentType("application/xml;charset=UTF-8");response.setHeader("pragma","no-cache");response.setHeader("cache-control","no-cache");if("admin".equals(userId)){response.getWriter().write("<root><success>true</success><tip>使用者名稱已存在</tip></root>");}else{response.getWriter().write("<root><success>false</success><tip>使用者名稱可以使用</tip></root>");}%>
介面
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>register.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"><script type="text/javascript" src="js/register.js"></script><script type="text/javascript" src="js/jquery-1.5.2.js"></script><style type="text/css">#round { padding:10px; width:300px; height:150px; border:1px solid #000; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius:10px; margin:10px auto;}#round div.user, #round div.pass {font-size:14px;color:#666;padding:15px 0;text-align:center;position: relative;}#round span{position: absolute;color:red;top:35px;left:100px;}#round input.text {width:200px;height:25px;border:1px solid #ccc;background:#fff;font-size:14px;}#round .button {padding:5px 0;text-align:center;}</style> </head> <body> <div id="round"> <form name="rgform" method="post" action="" > <div class="user"> 使用者名稱:<input type="text" name="username" id="username" onchange="事件調用的方法"> <span id="msg"></span> </div> <div class="pass"> 密 碼:<input type="password" name="password" id="password"> </div> <div class="button"><input type="button" value="提交"/></div> </form> </div> </body></html>
使用過jQuery非同步請求的方法的同學,肯定覺得那個相當好用,相比而言,上面寫的相當繁瑣,get方式和post方式請求甚至還有部分代碼是有很大區別的,那應如何通過代碼的方式屏蔽這些區別呢,這裡我們仿一下jQuery 的$.ajax() 方法。
//封裝ajaxfunction ajax(obj) {var xhr = creatXmlHttpRequest();obj.url = obj.url + '?rand=' + Math.random();obj.data = params(obj.data);if (obj.method === 'get') obj.url += obj.url.indexOf('?') == -1 ? '?' + obj.data : '&' + obj.data;if (obj.async === true) {xhr.onreadystatechange = function () {if (xhr.readyState == 4) {callback();}};}xhr.open(obj.method, obj.url, obj.async);if (obj.method === 'post') {xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send(obj.data);} else {xhr.send(null);}if (obj.async === false) {callback();}function callback() {if (xhr.status == 200) {obj.success(xhr.responseText);//回調傳遞參數} else {alert('擷取資料錯誤!錯誤代號:' + xhr.status + ',錯誤資訊:' + xhr.statusText);}}}
//名值對轉換為字串function params(data) {var arr = [];for (var i in data) {arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(data[i]));}return arr.join('&');}
調用我們封裝的ajax方法
window.onload = function(){document.getElementById("username").onchange = function(){ajax({method : 'post',url : 'checkuserByJSON.jsp',data : {'username' : document.rgform.username.value,'password' : document.rgform.password.value},success : function (text) {var _ret = eval('(' + text + ')'); document.getElementById("msg").innerHTML = _ret.tip;},async : true});}}
我們給ajax傳的就是一個object對象,是不是已經很貼近jQuery的方式了呢。