jquery中預設的ajax調用方法是非同步,因此稍不注意就會出錯。比如有一個例子,要求通過ajax檢查一個數是奇數還是偶數。某人不加思索的寫出如下的代碼:
- $(function () {
- $("#btntest").click( function(){
- var s=checkodd(5);
- alert(s);
- });
- });
-
- function checkodd(i) {
- var options = {
- type: 'POST',
- url: "test.ashx",
- data: { "i": i },
- success: function (result) {
- if (result.code > 0) {
- return "odd";
- }
- else {
- return "even";
- }
- },
- dataType: "json",
- error: function (result) {
- alert("error");
- }
- };
- $.ajax(options);
- }
其中test.ashx會在接到請求後,如果傳入的i是奇數則返回json格式的資料{"code":"1"},如果是偶數,則返回{"code":"-1"}。
寫下這樣的代碼後,運行後得到的結果如下:
650) this.width=650;" style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" title="clipboard" border="0" alt="clipboard" height="184" src="http://www.bkjia.com/uploads/allimg/131228/1235205Q6-0.png" />
這是因為success方法裡面的return,僅僅是對success方法的傳回值,而不是checkodd的傳回值,這樣的傳回值是無法直接由checkodd方法做得到的。
因此,某人修改代碼如下:
- function checkodd(i) {
- var returnvalue;
- var options = {
- type: 'POST',
- url: "test.ashx",
- data: { "i": i },
- success: function (result) {
- if (result.code > 0) {
- returnvalue = "odd";
- }
- else {
- returnvalue = "even";
- }
- },
- dataType: "json",
- error: function (result) {
- alert("error");
- }
- };
- $.ajax(options);
- return returnvalue;
- }
通過一個中間變數returnvalue來擷取傳回值。看上去還不錯。但是運行後得到的結果卻是:
650) this.width=650;" style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" title="clipboard[1]" border="0" alt="clipboard[1]" height="184" src="http://www.bkjia.com/uploads/allimg/131228/123520B09-1.png" />
原因很簡單,忽略了ajax預設情況下是非同步執行的,也就是說,在ajax方法沒有運行完,即success方法都沒運行完成之前,已經將returnvalue的值返回出去了,那當然就得到undefined的值。
jquery的ajax提供了async參數,通過設定該參數的值為false,可以避免非同步執行。因此,某人再次修改代碼:
- function checkodd(i) {
- var returnvalue;
- var options = {
- type: 'POST',
- url: "test.ashx",
- data: { "i": i },
- async:false,
- success: function (result) {
- if (result.code > 0) {
- returnvalue = "odd";
- }
- else {
- returnvalue = "even";
- }
- },
- dataType: "json",
- error: function (result) {
- alert("error");
- }
- };
- $.ajax(options);
- return returnvalue;
- }
這次終於對了。
650) this.width=650;" style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" title="clipboard[2]" border="0" alt="clipboard[2]" height="186" src="http://www.bkjia.com/uploads/allimg/131228/123520HA-2.png" />
async:false這樣設定,使得ajax必須執行完成後,才可執行下面的代碼,因此在適當的情況下,要修改ajax的參數來保證同步運行。
事實上,jquery的ajax本質上調用了XMLHttpRequest對象。XMLHttpRequest是一個API,各個瀏覽器對它都有各自的實現。比如老版本的IE用的是ActiveX, Firefox使用XMLHttpRequest對象。這個API主要實現javascript進行HTTP(S)通訊。詳細的說明可以參與維基百科http://en.wikipedia.org/wiki/XMLHttpRequest。
直接使用該API實現ajax比較費勁,可以看下面的代碼。
- function useXMLHttpRequest() {
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open("POST", "test.ashx", false);
- xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
- xmlhttp.onreadystatechange = function () {
- if (xmlhttp.readyState == 4) {
- //alert(xmlhttp.responseText);
- if (xmlhttp.responseText.code > 0) {
- alert("odd");
- }
- else {
- alert("even");
- }
- }
- };
- xmlhttp.send("i=5");
- alert("finished");
- }
上面的代碼實現了前面jquery的ajax的功能,編寫起來比較麻煩,要設定一些參數等等,其中xmlhttp.open("POST", "test.ashx", false);中,最後的參數false或者true是控制ajax為同步還是非同步,和前面的jquery的ajax例子中的一個意思。所以jquery對該API做了封裝,使得用jquery操作ajax更方便。
有一點要注意,Javascript自身是單線程啟動並執行,所有的主流瀏覽器只提供一個線程執行Javascript。因此Javascript不能開啟額外的線程除非使用Web Workers,目前最新的瀏覽器 Safari, Chrome, Opera and Mozilla Firefox支援Web Workers,IE10也會支援)。Javascript中的事件都是線性執行的,通過一個任務隊列,可以近似的看做先進先出的模式處理事件的,因此所有的Javascript非同步實現都是假象,通過計時器實現的。
Javascript自身單線程運行,不代表ajax是單線程運行,因為ajax是通過XMLHttpRequest這個API實現的,因此是瀏覽器提供額外的線程去處理http request。一旦請求處理完畢,它會觸發一個事件,把這個事件加入到javascript任務隊列中,直到javascript處理這個事件。
本文出自 “一隻部落格” 部落格,請務必保留此出處http://cnn237111.blog.51cto.com/2359144/1038080