熟悉web開發的程序員想必對Ajax也不會陌生。如今已經有不少js框架封裝了ajax實現,例如JQuery的ajax函數,調用起來很是方便。固然本文不打算講框架的使用,咱們將從Ajax的javascript源碼實現開始。javascript
var getXmlHttpRequest = function () { if (window.XMLHttpRequest) { //主流瀏覽器提供了XMLHttpRequest對象 return new XMLHttpRequest(); } else if (window.ActiveXObject) { //低版本的IE瀏覽器沒有提供XMLHttpRequest對象 //因此必須使用IE瀏覽器的特定實現ActiveXObject return new ActiveXObject("Microsoft.XMLHTTP"); } }; var xhr = getXmlHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { //獲取成功後執行操做 //數據在xhr.responseText } }; xhr.open("TYPE", "URL", true); xhr.send("");
能夠看到,xhr對象是經過onreadystatechange來監聽Ajax的最終完成狀況,這裏也迎來了此次要重點討論的主角:readyState和status。java
readyState是XMLHttpRequest對象的一個屬性,用來標識當前XMLHttpRequest對象處於什麼狀態。程序員
readyState總共有5個狀態值,分別爲0~4,每一個值表明了不一樣的含義,以下表所示:web
0 | 未初始化狀態:此時,已經建立了一個XMLHttpRequest對象 |
1 | 準備發送狀態:此時,已經調用了XMLHttpRequest對象的open方法,而且XMLHttpRequest對象已經準備好將一個請求發送到服務器端 |
2 | 已經發送狀態:此時,已經經過send方法把一個請求發送到服務器端,可是尚未收到一個響應 |
3 | 正在接收狀態:此時,已經接收到HTTP響應頭部信息,可是消息體部分尚未徹底接收到 |
4 | 完成響應狀態:此時,已經完成了HTTP響應的接收 |
status是XMLHttpRequest對象的一個屬性,表示響應的HTTP狀態碼。ajax
在HTTP1.1協議下,HTTP狀態碼總共可分爲5大類,以下表所示:瀏覽器
1XX | 服務器收到請求,須要繼續處理。例如101狀態碼,表示服務器將通知客戶端使用更高版本的HTTP協議。 |
2XX | 請求成功。例如200狀態碼,表示請求所但願的響應頭或數據體將隨此響應返回。 |
3XX | 重定向。例如302狀態碼,表示臨時重定向,請求將包含一個新的URL地址,客戶端將對新的地址進行GET請求。 |
4XX | 客戶端錯誤。例如404狀態碼,表示客戶端請求的資源不存在。 |
5XX | 服務器錯誤。例如500狀態碼,表示服務器遇到了一個不曾預料的狀況,致使了它沒法完成響應,通常來講,這個問題會在程序代碼出錯時出現。 |
爲何onreadystatechange的函數實現要同時判斷readyState和status呢?服務器
咱們知道 readyState === 4 已經表示了請求響應成功了,爲何還要後續的status呢?帶着問題,咱們開始來作一些試驗吧。框架
javascript端的實現代碼以下:函數
var getXmlHttpRequest = function () { if (window.XMLHttpRequest) { return new XMLHttpRequest(); } else if (window.ActiveXObject) { return new ActiveXObject("Microsoft.XMLHTTP"); } }; var xhr = getXmlHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { alert(xhr.responseText); } }; xhr.open("GET", "/data.aspx", true); xhr.send("");
這個演示DEMO使用ASP.NET Webform框架,如今咱們在後臺data.aspx作一些手腳,不如讓它報錯試試!C#代碼以下:性能
public partial class data : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { throw new Exception("Error"); } }
運行javascript代碼,提示窗口出現了以下:
服務響應出錯了,但仍是返回了信息,這並非咱們想要的結果。打開Fiddler監控,能夠看到data.aspx返回的是500響應,但因爲只使用readystate作判斷,它不理會放回的結果是500仍是200,只要響應成功返回了,就執行接下來的javascript代碼,結果將形成各類不可預料的錯誤。因此只使用readyState判斷是行不通的。
換另一個角度想,狀態碼返回200就表示此次響應是成功的了,那麼是否是能夠不使用readyState,單獨只使用status作判斷呢?好,帶着問題,繼續來作試驗吧。
javascript端的代碼實現以下:
var getXmlHttpRequest = function () { if (window.XMLHttpRequest) { return new XMLHttpRequest(); } else if (window.ActiveXObject) { return new ActiveXObject("Microsoft.XMLHTTP"); } }; var xhr = getXmlHttpRequest(); xhr.onreadystatechange = function () { if (xhr.status === 200) { alert("readyState=" + xhr.readyState + xhr.responseText); } }; xhr.open("GET", "/data.aspx", true); xhr.send("");
此次將在data.aspx後臺作處理,讓它只返回一個字符串,實現以下:
public partial class data : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Response.Write("Test"); Response.End(); } }
一切都是那麼地天然,是否是隻要彈出一個寫着一行"readyState=4Test"的字符串的提示框,就表示結果成立了?把它跑起來了吧,結果已經就離咱們不遠了!
事實上,結果卻不像預期那樣。響應碼確實是返回了200,可是總共彈出了3次窗口!第一次是「readyState=2」的窗口,第二次是「readyState=3Test」的窗口,第三次是「readyState=4Test」的窗口。由此,可見onreadystatechange函數的執行不是隻在readyState變爲4的時候觸發的,而是readyState的每次變化都會觸發,因此就出現了前面說的那種狀況。可見,單獨使用status判斷也是行不通的。
由上面的試驗,咱們能夠知道判斷的時候readyState和status缺一不可。那麼readyState和status的前後判斷順序會不會有影響呢?咱們能夠將status調到前面先判斷,代碼如 xhr.status === 200 && xhr.readyState === 4。
事實上,這對於最終的結果是沒有影響的,可是中間的性能就不一樣了。由上一個試驗咱們知道,readyState的每次變化都會觸發onreadystatechange函數,假如先判斷status,那麼每次都會多判斷一次status的狀態。雖然性能上影響甚微,不過咱們仍是應該抱着追求極致代碼的想法,把readyState的判斷放在前面。
若是你有新的想法,歡迎留言討論。
參考資料: 鋒利的JQuery, http狀態碼維基百科