2012-06-11 41 views
4

我曾經在一個網絡工作者下面的代碼:多個Web工作者Ajax請求,而不是所有返回

self.addEventListener('message', function(e){ 
     try { 
     var xhr=new XMLHttpRequest() 

     for(var i = 0; i < e.data.urls.length;i++){ 
     xhr.open('GET', e.data.urls[i], true); 
     xhr.setRequestHeader('Accept', 'application/json'); 
     xhr.send(null); 
     xhr.onreadystatechange = function() { 
       if (xhr.readyState == 4) { 
        if (xhr.status == 200 || xhr.status == 304 || xhr.status ==0) { 
        postMessage(xhr.responseText); 
        } else { 
        postMessage(xhr.status + xhr.responseText); 
        throw xhr.status + xhr.responseText; 
        } 
       } 
     }; 
     } 
    } catch (e) { 
    postMessage("ERROR:"+e.message);  
    } 
}, false); 

e.data.urls包含16個請求,這是在UI線程處理是這樣的:

var replies = 0; 

worker.addEventListener('message', function(e){ 
    replies += 1; 
}); 

只有10個請求完成,這是因爲在所有請求返回之前UI線程已經停止,還是有其他東西丟失?

+1

評論指出,發送一個AJAX請求,只是從發佈你的工人的消息的代碼。你看到多少個回覆? – akonsu

+0

16條消息以正常的postMessage調用返回,這是正確的數量。必須是同步的東西。 – dagda1

+0

可並行運行的xhr請求數量有限制。你可以使用'xhr.open('GET',e.data.urls [i],false)嘗試同步嗎? – pd40

回答

3

這裏發生的事情是你的xhr變量在循環中被覆蓋。由於XMLHttpRequest的性質,即它在默認情況下是異步的,在xhr.send();行執行沒有等待之後,for進入下一個循環,並且xhr.[...]行對上一個循環中建立和觸發的對象xhr進行操作。根據前一個循環的請求是否已經返回(並因此執行了狀態更改處理程序)或不是(這是相當不可預測的),您將覆蓋「實時」或「已刪除」對象。那些在完成之前被覆蓋的信息將會丟失。

你應該確保你不覆蓋。不要對相同的XMLHttpRequest對象進行操作,而是爲每個請求實例化一個新的對象。

我移動了循環外的處理函數的定義。沒有必要在每個循環中重新定義它。它在分配給它的XMLHttpRequest實例的上下文中調用,所以this指向實例。

此外,我交換了xhr.send()xhr.onreadystatechange = ...行。狀態更改事件處理程序應在發送請求之前分配(從發送開始時有多個事件觸發),儘管不太可能,但是在添加事件處理程序的行之前,請求甚至可以以就緒狀態4返回在代碼中執行。

self.addEventListener('message', function(e){ 

    var xhrs = []; 

    function handler() { 
     if (this.readyState == 4) { 
     if (this.status == 200 || this.status == 304 || this.status ==0) { 
      postMessage(this.responseText); 
     } else { 
      postMessage(this.status + this.responseText); 
      throw this.status + this.responseText; 
     } 
     } 
    }; 

    for(var i = 0; i < e.data.urls.length;i++) { 
     xhrs[i] = new XMLHttpRequest(); 
     xhrs[i].open('GET', e.data.urls[i], true); 
     xhrs[i].setRequestHeader('Accept', 'application/json'); 
     xhrs[i].onreadystatechange = handler; 
     xhrs[i].send(null); 
    } 

}, false); 
+0

我可以看到你的觀點,但我真的不認爲這是問題,因爲它完美的UI分支。只有在web worker文件上運行時,報告的行爲纔會發生。 – dagda1

+1

那麼,發佈的版本肯定會產生描述的「重寫」行爲。您是否按照建議修改了代碼? 也許有一個因素會影響代碼的執行速度,在兩種情況下會有所不同。 – marekful

+0

我相信,如果您進行建議的更改,您會收到儘可能多的回覆,與您發送的請求數量一樣多。 – marekful

0

你的例子類似於this firefox example除了進行多AJAX請求工人內部的循環。我很想知道是什麼導致了失敗。您可能會限制單個工作人員可以處理的併發連接數量。

你能嘗試移動網址環路主界面線程:

for(var i = 0; i < urls.length; i++){ 
    worker.postMessage(urls[i]); 
} 

,改變你的工人在一個時間只是做一個AJAX調用

self.addEventListener('message', function(e){ 
    try { 
     var xhr=new XMLHttpRequest() 

     xhr.open('GET', e.data, true); 
     xhr.setRequestHeader('Accept', 'application/json'); 
     xhr.send(null); 
     xhr.onreadystatechange = function() { 
       if (xhr.readyState == 4) { 
        if (xhr.status == 200 || xhr.status == 304 || xhr.status ==0) { 
        postMessage(xhr.responseText); 
        } else { 
        postMessage(xhr.status + xhr.responseText); 
        throw xhr.status + xhr.responseText; 
        } 
       } 
     }; 
    } catch (e) { 
     postMessage("ERROR:"+e.message);  
    } 
}, false); 

看看是否有用?


mozilla example有一些錯誤處理程序,可能會顯示問題。您可以嘗試添加在主界面線程:

worker.onerror = function(error) { 
    dump("Worker error: " + error.message + "\n"); 
    throw error; 
}; 

,工人裏面:

function errorReceiver(event) { 
    throw event.data; 
}