jQuery中默認(rèn)的Ajax調(diào)用方法是異步的掀序,因此稍不注意就會出錯帆焕。比如有一個例子,要求通過Ajax檢查一個數(shù)是奇數(shù)還是偶數(shù)不恭。
某人不加思索的寫出如下的代碼:
$(function () {
$("#btntest").click( function(){
var s=checkodd(5);
alert(s);
});
});
function checkodd(i) {
var options = $.ajax({
type: 'POST',
url: "test.php",
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.php會在接到請求后叶雹,如果傳入的i是奇數(shù)則返回json格式的數(shù)據(jù){"code":"1"},如果是偶數(shù),則返回{"code":"-1"}换吧。
寫下這樣的代碼后折晦,運行后得到的結(jié)果:
undefined
這是因為success方法里面的return,僅僅是對success方法的返回值沾瓦,而不是checkodd的返回值满着,這樣的返回值是無法直接由checkodd方法做得到的。
因此贯莺,某人修改代碼如下:
function checkodd(i) {
var returnvalue;
var options = {
type: 'POST',
url: "test.php",
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來獲取返回值漓滔。看上去還不錯乖篷。但是運行后得到的結(jié)果卻是:
undefined
原因很簡單,忽略了Ajax默認(rèn)情況下是異步執(zhí)行的透且,也就是說撕蔼,在Ajax方法沒有運行完,即success方法都沒運行完成之前秽誊,已經(jīng)將returnvalue的值返回出去了鲸沮,那當(dāng)然就得到undefined的值。
jQuery的Ajax提供了async參數(shù)锅论,通過設(shè)置該參數(shù)的值為false讼溺,可以避免異步執(zhí)行。因此最易,某人再次修改代碼:
function checkodd(i) {
var returnvalue;
var options = {
type: 'POST',
url: "test.php",
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;
}
這次終于對了怒坯。
odd
async:false這樣設(shè)置炫狱,使得Ajax必須執(zhí)行完成后,才可執(zhí)行下面的代碼剔猿,因此在適當(dāng)?shù)那闆r下视译,要修改Ajax的參數(shù)來保證同步運行。
事實上归敬,jQuery的Ajax本質(zhì)上調(diào)用了XMLHttpRequest對象酷含。XMLHttpRequest是一個API,各個瀏覽器對它都有各自的實現(xiàn)汪茧。比如老版本的IE用的是ActiveX, Firefox使用XMLHttpRequest對象椅亚。這個API主要實現(xiàn)javascript進行HTTP(S)通信。詳細(xì)的說明可以參與維基百科
http://en.wikipedia.org/wiki/XMLHttpRequest舱污。
直接使用該API實現(xiàn)Ajax比較費勁呀舔,可以看下面的代碼。
function useXMLHttpRequest() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "test.php", 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");
}
上面的代碼實現(xiàn)了前面jQuery的Ajax的功能慌闭,編寫起來比較麻煩别威,要設(shè)置一些參數(shù)等等
其中```
xmlhttp.open("POST", "test.php", false);
最后的參數(shù)false或者true是控制Ajax為同步還是異步,和前面的jQuery的Ajax例子中的一個意思驴剔。
>所以jQuery對該API做了包裝省古,使得用jQuery操作Ajax更方便。
有一點要注意:
>Javascript自身是單線程運行的丧失。
>所有的主流瀏覽器只提供一個線程執(zhí)行Javascript豺妓。
因此Javascript不能開啟額外的線程
(除非使用Web Workers,目前最新的瀏覽器 Safari, Chrome, Opera and Mozilla Firefox支持Web Workers布讹,IE10也會支持)
Javascript中的事件都是線性執(zhí)行的琳拭,通過一個任務(wù)隊列,可以近似的看做先進先出的模式處理事件的描验,因此所有的Javascript異步實現(xiàn)都是假象白嘁,通過計時器實現(xiàn)的。
Javascript自身單線程運行膘流,不代表Ajax是單線程運行絮缅,因為Ajax是通過XMLHttpRequest這個API實現(xiàn)的,因此是瀏覽器提供額外的線程去處理http request呼股。一旦請求處理完畢耕魄,它會觸發(fā)一個事件,把這個事件加入到j(luò)avascript任務(wù)隊列中彭谁,直到Javascript處理這個事件吸奴。