Numerous web worker asynchronous requests are being made, but not all are coming back

Within my web worker script, I am utilizing the following code:

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);

The array e.data.urls contains 16 separate requests which are received and processed on the UI thread through the following code snippet:

var replies = 0;

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

However, only 10 of the requests seem to be completing. I wonder if this is due to the UI thread halting before all responses have been returned, or if there may be another element that I am overlooking?

Answer №1

What's going on here is that the `xhr` variable is being overwritten in the loop. Because `XMLHttpRequest` is asynchronous by default, the code after `xhr.send();` doesn't wait for it to finish, causing the next loop iteration to start and operate on the previous `xhr` object. Depending on whether the previous request has completed or not, you may end up overwriting a live or finished `xhr` object, resulting in lost data.

To avoid this, make sure to use a new instance of XMLHttpRequest for each request instead of overwriting the same object.

I've moved the definition of the handler function outside the loop so it doesn't need to be redefined every time. The handler will be called in the context of the assigned XMLHttpRequest instance, making `this` point to the correct object.

Additionally, I've swapped the order of lines between `xhr.send()` and `xhr.onreadystatechange = ...`. It's important to assign the event handler before sending the request as there are events fired immediately after send. There's a rare chance that a request might return with ready state 4 before the event handler line is executed.

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);

Answer №2

It seems that your example bears a resemblance to this firefox demonstration, with the exception of the loop within the worker making numerous ajax requests. I wonder what could be the cause of the failure in processing these requests. It's possible that the worker is reaching a limit on the number of concurrent ajax connections it can handle.

Have you considered relocating the url for loop to the main gui thread:

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

Additionally, you may want to modify your worker to perform one ajax call at a time:

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);

You could try implementing some error handlers from the mozilla example to troubleshoot the issue. For instance, adding the following code in the main GUI thread:

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

And inside the worker:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to open a print preview in a new tab using Angular 4

Currently, I am attempting to implement print functionality in Angular 4. My goal is to have the print preview automatically open in a new tab along with the print popup window. I'm struggling to find a way to pass data from the parent window to the c ...

Encountering issues when attempting to send a POST request using Rails, React, and jQuery

I am a beginner in the world of React and I'm currently working on building a Twitter-like app for practice purposes. Although I managed to successfully retrieve a list of my tweets, I have hit a roadblock when it comes to posting a new tweet using AJ ...

Is it possible to execute an ajax function at regular intervals until a specific condition is fulfilled?

My application consists of two JSP pages. One is responsible for the UI, while the other processes the response. UICounter.jsp: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Page</titl ...

Issue with onclick event not being triggered by Javascript function inside constructor

My current challenge involves implementing a function called makeHighlight within the SmartButton constructor. The purpose of this function is to execute whenever I click on the SmartButton object, which is represented by an image element. To achieve thi ...

Using JQuery to Identify the Clicked Div Container

Currently working on a JQuery script to determine which specific div box was clicked, but running into some issues. I understand that there are other approaches to achieve this by directly invoking functions upon clicking a div box, but I want to first ide ...

manipulating session variables with javascript ajax and php

I'm struggling with setting and retrieving session variables using JavaScript code that calls PHP functions via AJAX. I want to access the returned session field in my JavaScript, but nothing seems to be working. Can someone take a look at my code and ...

Is there a way to set the content to be hidden by default in Jquery?

Can anyone advise on how to modify the provided code snippet, sourced from (http://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_hide_show), so that the element remains hidden by default? <!DOCTYPE html> <html> <head> <scrip ...

How to showcase a list from intricate JSON data using Angular

I recently came across this pre-existing JSON data that I am unable to change: {"tags": [ { "title": "news", "options": [ { "title": "important", }, { "title": "less important", ...

AJAX Finished Reply

I have successfully implemented a password change function on my website, but I am encountering an issue with displaying a success or fail message. Here is the structure of my HTML code: <form id="change_Pass" action="" method="post"> //stuff ...

Why must the sidebar be displayed horizontally on the smartphone screen?

I've been struggling to make the sidebar menu on my smartphone display horizontally with icons at the top and text at the bottom. I've tried using flex and other methods, but it still doesn't work sideways. Am I missing something? const s ...

Ajax returns with a successful response, yet the specified action is never executed

Currently assisting with a plugin build on Wordpress and facing an issue with a basic ajax call. I am attempting to pass an object through the method 'grab_object_from_ajax_call,' but the method is not executing as expected. Below is the JavaScri ...

What could be the reason for the jQuery animate function not functioning properly?

I am having an issue with this code. I have followed the syntax for animate() but it is not working as expected. <!DOCTYPE html> <html> <head> <style> #testing { background-color: skyblue; Position: absolute; ...

A guide to entering information into an input field with JavaScript for logging in successfully

https://i.stack.imgur.com/TF51Z.gif https://i.stack.imgur.com/HHsax.png https://i.stack.imgur.com/HUztt.png When attempting to input text using document.getelement('').value="" , it doesn't behave as expected. The text disappear ...

How can I retrieve the children of a component in React?

Currently, I am working on implementing Class Components for a project involving a main picture and a smaller pictures gallery stored in an array. The overall structure consists of an all pictures container that houses both the main picture and smaller pic ...

AngularJS is a highly intuitive platform that incorporates Google Maps for

I am relatively new to using Angular and decided to experiment with integrating Google Maps into my project. Here's what I need: I have a search bar for finding restaurants. The API returns the address, latitude, and longitude of the restaurant searc ...

Why does serializing a JavaScript Object to JSON result in "{}"?

Hello fellow developers, I'm currently working on setting up a LocalStorage feature for my web application. One issue I've come across is that all objects in the Model abstraction layer need to be serialized. I understand that functions aren&a ...

The candy stripes on a loading bar zebra assist in creating a unique and

I'm in the process of creating my portfolio and I'd like to incorporate unique animated loading bars, such as vertical or horizontal candy stripes, to showcase my coding skills. Can anyone suggest a specific programming language or tool that woul ...

Tips for personalizing error messages for the "required" field by utilizing a dictionary feature on VeeValidate in Vue.Js

I am trying to update the error message that appears when an input field with the "cpf" rule is left empty (meaning it does not meet the "required" rule). I believe using the "dictionary method" with custom messages is the solution, but I am struggling to ...

Displaying JSON data in an HTML table cell format

Hey everyone, I need some help with the following task: I am working on displaying a list of log lines in an HTML table. Some of these lines will contain JSON strings, and I want to format the JSON data within the table when the HTML file is loaded from ...

Is there a way to stop myself from accidentally clicking twice on the same tile?

I'm currently working on a game and facing an issue where my "X" gets deleted when clicking twice on the same tile. I am able to move my "X" around, but the double-click deletion is causing trouble. I attempted using booleans but struggle with them. I ...