4

Web ワーカーに次のコードがあります。

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 には、UI スレッドで次のように処理される 16 のリクエストが含まれています。

var replies = 0;

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

10 個のリクエストしか完了していません。これは、すべてのリクエストが返される前に UI スレッドが停止したためですか、それとも他に何か不足していますか?

4

2 に答える 2

3

ここで起こっていることは、xhr変数がループで上書きされることです。の性質上XMLHttpRequest、つまりデフォルトでは非同期であり、xhr.send();行の実行が待機せずforに次のループに入り、前のループで設定および起動されxhr.[...]たオブジェクトに対して行が動作します。xhr前のループのリクエストが返されたか (したがって、状態変更ハンドラーが実行されたか)、否か (これはまったく予測できません) に応じて、「ライブ」オブジェクトまたは「終了」xhrオブジェクトのいずれかを上書きします。完了する前に上書きされたものは失われます。

上書きしないようにする必要があります。同じ XMLHttpRequest オブジェクトを操作するのではなく、リクエストごとに新しいオブジェクトをインスタンス化してください。

ハンドラ関数の定義をループ外に移動しました。各ループで再定義する必要はありません。これは、割り当てられている XMLHttpRequest インスタンスのコンテキストで呼び出されるためthis、インスタンスを指します。

また、 と 行を入れ替えましxhr.send()xhr.onreadystatechange = ...。状態変更イベント ハンドラーは、リクエストが送信される前に割り当てる必要があります (送信の開始直後からいくつかのイベントが発生します)。可能性は低いですが、イベント ハンドラーを追加する行の前に、リクエストが Ready 状態 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);
于 2012-06-12T12:46:26.003 に答える
0

あなたの例は、複数のajaxリクエストを行うワーカー内のループを除いて、このFirefoxの例に似ています。何が失敗の原因なのか知りたいです。1人のワーカーが処理できる同時ajax接続の数に制限がある可能性があります。

ループのURLをメインのGUIスレッドに移動してみてください。

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

一度に1つの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の例には、問題を明らかにする可能性のあるエラーハンドラーがいくつかあります。メインのGUIスレッドに追加してみてください。

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

と労働者の内部:

function errorReceiver(event) {  
   throw event.data;  
}  
于 2012-06-13T00:47:51.783 に答える