多个 Web Worker ajax 请求,但并非所有请求都返回

Multiple Web Worker ajax requests and not all returning

本文关键字:请求 返回 Web Worker ajax 多个      更新时间:2023-09-26

我在 Web worker 中有以下代码:

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

这里发生的事情是你的xhr变量在循环中被覆盖。由于XMLHttpRequest的性质,也就是说,默认情况下它是异步的,在xhr.send();行执行不等待之后for进入下一个循环,并且xhr.[...]行在上一个循环中设置和触发的xhr对象上运行。根据前一个循环的请求是否返回(以及因此执行的状态更改处理程序)或是否返回(这是非常不可预测的),您可以覆盖"实时"或"Finshed"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);

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

您能否尝试将循环的网址移动到主 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;  
}