4

我在网络工作者中有以下代码:

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 线程在所有请求返回之前就停止了,还是我还缺少其他东西?

4

2 回答 2

3

这里发生的是您的xhr变量在循环中被覆盖。由于 的性质XMLHttpRequest,即默认是异步的,xhr.send();行执行后不等待所以for进入下一个循环,xhr.[...]行对上一个循环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);
于 2012-06-12T12:46:26.003 回答
0

您的示例与此 firefox 示例类似,但工作人员内部的循环发出多个ajax请求。我很想知道是什么导致了失败。您可能会遇到单个工作人员可以处理的并发ajax连接数的限制。

您能否尝试将 url for 循环移动到主 gui 线程:

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 示例有一些错误处理程序可能会揭示问题。您可以尝试在主 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 回答