2013-10-09 124 views
0

首先,我已經看了相關的SO問題,並沒有找到一個合適的解決方式很多,所以這裏有雲:的Javascript:使用AJAX異步同步

我一直工作在一個HTML/Javascript頁面充當後端服務器的用戶界面。我在完成AJAX時使用了同步調用(也就是var xmlhttp = new XMLHttpRequest(); xmlhttp.open(type, action, false);),但是現在已經發現Mozilla顯然不喜歡同步請求,因此不贊同它們中一些非常需要的功能。

引述https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

注:與壁虎11.0開始(火狐11.0 /雷鳥11.0/SeaMonkey的2.8),以及WebKit的興建528,這些瀏覽器不再讓你使用的responseType屬性進行時同步請求。試圖這樣做會引發NS_ERROR_DOM_INVALID_ACCESS_ERR異常。這一變化已經提交給W3C進行標準化。

這樣很好。我即將需要有條件地更改響應類型,但它不起作用。現在我打算在中包裝一個AJAX異步請求,它將模擬同步性。

以下是我的代碼使用的通用「make web request」函數,我已經開始適應我的工作目的。不幸的是,它不像我希望的那樣工作。

var webResponse = null; 

function webCall(action, type, xmlBodyString) { 
console.log("In webCall with " + type + ": " + action); 
webResponse = null; 
var xmlhttp = new XMLHttpRequest(); 
xmlhttp.onreadystatechange = function() 
{ 
    if (xmlhttp.readyState == 4) 
    { 
     if (xmlhttp.status == 200) { 
      webResponse = xmlhttp.responseXML; 
     } else { 
      var statusTxt = xmlhttp.statusText; 
      if (statusTxt == null || statusTxt.length == 0) { 
       statusTxt = "An Unknown Error Occurred"; 
      } 
      throw "ERROR " + xmlhttp.status + ":" + statusTxt; 
     } 
    } 
} 
xmlhttp.open(type, action, true); 
if (xmlBodyString == null) { 
    xmlhttp.send(); 
} else { 
    xmlhttp.setRequestHeader("Content-Type", "text/xml"); 
    xmlhttp.send(xmlBodyString); 
} 

for (var i = 0; i < 20; i++) { 
    if (webResponse != null) { 
     break; 
    } 
    window.setTimeout(nop, 250); 
} 
if (webResponse == null) { 
    throw "Waited 5 seconds for a response, and didn't get one."; 
} 
console.log("Responding with " + webResponse); 
return webResponse; 
} 

function nop() { 
} 

所以,我認爲這是非常直接的。創建一個全局變量(回想起來,它可能甚至不必是全局的,但現在,w/e),設置onreadystatechange在它準備好之後爲它賦值,創建異步請求,等待最大值5秒內全局變量不爲空,然後返回它或拋出一個錯誤。

問題是我的代碼實際上並沒有等待5秒鐘。相反,它立即退出,聲稱它在等待5秒鐘之後才這樣做。

我做了一個小提琴,它的價值。它在那裏也不起作用。 http://jsfiddle.net/Z29M5/

任何幫助,非常感謝。

+0

爲什麼你使用同步ajax請求?這不是什麼阿賈克斯是 – lukaleli

+0

我無法想象爲什麼你會*需要*改變responseType,而不僅僅是發現它很方便。一個字符串總是可以解碼的。 – hobbs

+0

你可能不需要它們是同步的。只需讓他們使用回調一個接一個地開火。 – Blender

回答

2

你不能這樣做。堅持異步請求。回調地獄很糟糕,但這就是你在沒有語言支持的事件驅動系統中所獲得的。

目前在瀏覽器中根本沒有辦法在普通JavaScript中模擬同步代碼。

如果你能嚴重限制自己支持的瀏覽器的設置(幾乎只是火狐目前據我所知),你可以得到synchronous- 使用發電機尋找代碼。

也有語言編譯成JS並支持同步代碼。我能想到的一個例子(從幾年前)是這樣的:https://github.com/maxtaco/tamejs

+0

回調地獄確實吸吮,這就是我想要避免的。我開始產生這樣的印象,那就是我將要堅持的。 –

1

首先,對於所有的痛苦,異步使用異步代碼是最好的選擇。它採用不同的方法,就是這樣。

其次,對於您的具體問題,這就是你的「延遲」循環做:

For twenty iterations 
    if we've had a response, break 
    set a timeout for 250ms 
go round again 

(整個for循環立即完成全部20次迭代你不會有響應)

。 。 。 後250毫秒

執行第一setTimeout回調,這是nop

執行第二...

我想不出一個快速的方法來解決這個問題,除了把你的處理代碼AJAX回調,無論如何,它都是異步代碼。

0

爲什麼不創建一個請求數組,只要從前一個ajax調用中獲得響應,就一個接一個地將它們彈出。