Using Javascript closures for managing asynchronous Ajax requests within for loops

Let's consider the arrays provided below.

var clients = ['a','b'];
var reports = ['x','y','z'];
var finalData = [];

Now, I aim to iterate through them in a specific manner as shown.

for(var i=0;i<reports.length;i++){
   var response = {report : reports[i]}
   for(var j=0;j<clients;j++){
       response.client = clients[i];
      $.ajax({
        url :url,
        success : function(data){
          response.data = data;
          finalData.push(response);
        })
     });
   }
}

However, due to asynchronous nature of ajax calls, it fails to work properly. To solve this issue, I intend to encapsulate this logic within the componentDidMount function of a react.js component and update the state with the finalData.

I attempted to use $.each instead of a traditional for loop and tried using .bind(this) to correctly update the state with finalData, but without success. I read that closures should be utilized for handling async calls effectively, however, I am unsure how to implement that here. The desired output is as follows:

finalData = [
        {client:a,report:x,data : 'xyz'},
        {client:b,report:x,data : 'xyz'},
        {client:a,report:y,data : 'xyz'},
        {client:b,report:y,data : 'xyz'},
        {client:a,report:z,data : 'xyz'},
        {client:b,report:z,data : 'xyz'}
     ]

Answer №1

To ensure the accuracy of your response variable, it is important to save the scope using closure. Consider implementing the following approach:

for(var i=0;i<reports.length;i++){
   var response = {report : reports[i]}
   for(var j=0;j<clients;j++){
      response.client = clients[i];

      (function(responce){
      $.ajax({
        url :url,
        success : function(data){
          response.data = data;
          finalData.push(response);
        })
      })(responce);

     });
   }
}

For a better understanding, let's simulate an ajax call using setTimeout in this example:

Imagine a scenario where we iterate a loop 5 times and aim to print the value of i after one second. Expected output: 0 1 2 3 4. However, due to the loop completing before the one-second delay, the actual output may be 5 printed five times instead.

for(var i=0;i<5;i++){
  setTimeout(function(){
    console.log(i);
    console.log("....");
  }, 1000) 
}

To resolve this issue, we need to encapsulate the value of i using closure, ensuring that the correct value is retrieved after the timeout:

for(var i=0;i<5;i++){
  (function(i){
    setTimeout(function(){
      console.log(i);
      console.log("....");
    }, 1000)
  })(i);
}

By applying this method, the code will print 0 1 2 3 4 as intended, which aligns with the solution provided in your example.

When updating the state, you have two options: either update it each time a value is received or check for completion before updating the state:

// Add this line at the beginning of the two for loops
var that = this;
finalData.push(response);
this.setState({data: finalData})
// Calculate 'total' by multiplying the number of reports by the number of clients
if(finalData.length == total){
  this.setState({data: finalData})
}

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

Getting the location of a mouse click and adding tags (marks) on an image: a simple guide

Is there a way to incorporate images with tagged marks similar to Facebook's image tagging feature? How can I retrieve the X and Y coordinates of tags on the image itself (not the screen) and display them in a responsive manner? ...

Issues with routing in NodeJS Express causing routes to not be called

I've been working on setting up a basic REST API using nodeJS. However, I am facing an issue where none of the endpoints are being called when I try to access them. Can someone guide me on what changes I need to make in order to get it working properl ...

Learn the process of assigning the present date using the jQuery UI date picker tool

I am looking to implement the feature of setting the current date using Angular/Jquery UI date picker. I have created a directive specifically for this purpose which is shown below: app.directive('basicpicker', function() { return { rest ...

Tips for Successfully Sending Vue Data in Axios POST Call

I'm struggling to pass Vue data to an axios.post request. Using the Vue template doesn't seem to work. How can I successfully pass the Data? Here is my Code: <body> <div id="app" class="container"> <div> ...

Tips for disabling viewport resizer while accessing the Console panel in Chrome using Control+Shift+J

Currently, I am utilizing the viewport resizer in Chrome to preview how my code appears on various devices. However, I have encountered an issue - whenever I try to access the console using ctrl + shift + j, the viewport resizer opens instead. You can obs ...

Gathering the presently unfinished observables within a superior-level rxjs observable

As an illustration, let's consider a scenario where I have a timer that emits every 5 seconds and lasts for 10 seconds. By using the scan operator, I can create an observable that includes an array of all the inner observables emitted up until now: c ...

Can we add to the input field that is currently in focus?

Recently, I've been working on a bookmarklet project. My goal is to append an element to the currently focused input field. For instance, if a user clicks on a textarea and then activates my bookmarklet, I want to insert the text "Hello" into that sp ...

When initiating a form submission through a prototype request, a dialog box titled "Choose an application to open with..." will unexpectedly emerge

My HAML form is submitted using the following jQuery code: $('appt_form').request({ onComplete: function(){ ... } }) During testing, my controller returns: render :json => {:name => "Ted"}.to_json However, this causes a ...

What is the proper way to manage the refresh token on the client's end within a JWT system?

Curious about what exactly occurs on the client side when the refresh token expires. Is the user directed to a login page and remains logged in, or does the client side log them out automatically? My understanding is that the refresh token is saved in an ...

The environmental variables stored in the .env file are showing up as undefined in Next.js 13

I am having trouble accessing the environment variables stored in my .env.local file within the utils folder located in the root directory. When I try to console log them, they show as undefined. console.log({ clientId: process.env.GOOGLE_ID, clien ...

Monitoring user logins based on user identification

How can I effectively monitor the activity of users who have logged into a web application that is managed by an external company? Despite my extensive research efforts, as a non-technical individual, I am struggling to understand how to utilize Google Ana ...

Omit specific object properties within a foreach loop in jQuery AJAX

Check Out This Fiddle Example I am currently working with a PHP file that returns JSON data for main content along with an additional property for pagination. I am looking for a way to exclude the pagination property when iterating over the data in a fore ...

ASP.NET Core Ajax response is empty

function addNewTeam() { var teamName = $("teamField").val(); $.ajax({ type: "POST", url: 'AddNewTeam', contentType: "application/json;", data: { team: "HELLO H ...

Steps for incrementing a number in an integer field with Node.js and MongoDB

I have a dataset that looks like this: { "_id": "6137392141bbb7723", "email": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="95f7e7fafafef0d5f6f4f2f9f0bbf6faf8">[email protected]</a>", ...

Sequelize does not automatically include a junction table in the associated model data

Imagine having two models, User and Event, established in a many-to-many relationship with User.belongsToMany(Event) and Event.belongsToMany(User). Everything seems to be functioning properly until executing User.findAndCountAll({include: [{model: Event}]} ...

Exploring the functionality of closing Material UI Drawer on escape key in a React 16 app with RTL support

I am currently experimenting with the Material UI Drawer component. I expected it to close when pressing the Esc key or clicking outside of it, but unfortunately, it is not behaving as anticipated. I am utilizing the react testing library for my tests an ...

Using jQuery's toggle function with a double click event to change the display to none

A div I created has the ability to expand to full screen upon double click, and I now wish to implement a toggle function so it can return to its original size when double clicked again. Initially, the code successfully increased the size of the div. Howe ...

Exploring CountUp functionality with Vue framework

I'm still getting the hang of Vue and recently completed my first project following a tutorial. This project is my first solo endeavor. Currently, I am working on a basic page to display the scores between two teams. The scores are retrieved from an ...

Combine several pages from PDF files into a single document

I am currently working on developing a small electron application that combines multiple PDF files or pages into one larger page to help save paper when printing several CAD drawings. Essentially, I am looking for a cross-platform solution similar to the ...

Error in Browserify Express App: Unexpected token while parsing the file

I have been attempting to browserify a javascript file. When I run the command: browserify global.js -o bundle.js An error message is returned: Error: Parsing file C:\ocquiz\public\javascripts\global.js: Unexpected token (756 ...