A Guide to Executing Asynchronous Function Calls in a For Loop using JavaScript

Experiencing issues with asynchronous calls within a for loop in my code. The loop progresses before the async call is completed, causing unexpected behavior. As someone new to this language, I'm trying to understand callbacks and other related concepts. I've experimented with self-calling functions, promises, and timeouts, but haven't achieved the desired flow.

The goal is to ensure that the firebase call finishes before adding the profile object to the messages array.

// Retrieving chats associated with the user
Chat.allChatsByUser(uid).$loaded()
 .then(function(data) {     
   for (var i = 0; i < data.length; i++) {
   // Utilizing a self-calling function to handle async callbacks
   // Ensuring the async call is executed during each iteration of the loop
   (function(i) {
      var item = data[i];
      // Fetching profile information for the matched user
      Auth.getProfile(item.$id).$loaded()
      .then(function(profile) { 
         // Handling success case
         if (typeof profile === 'object') { 
              if(chat.keyOrder == 'true') {

              // Retrieving last chat from firebase
              // DESIRE THIS TO COMPLETE BEFORE PROCEEDING                       
              ref.child('chatting').child('messages').child(chat.chatId).on("value", function(data) {
                 profile.lastChat = data.child('lastMsg').val();
              });

             // Adding chatting user's profile to the array
             chat.messages.push(profile);    

         } else {
               // Invalid response
               return $q.reject(profile);
         }
 }, function(profile) {
   // Promise rejected
   console.log('error', error);});
 })(i);
}

Any help or guidance would be greatly appreciated.

Regards, Noel

Answer №1

It seems like your requirements are two-fold: first, you need the loop to wait until the async call is finished before continuing. While there are sophisticated methods in ES6 to achieve this, since you're not utilizing ES6, I've implemented a workaround using a while loop. Secondly, you want to make sure the firebase call completes before adding the profile object to the messages array. To accomplish this, simply place the push call inside the value event handler as suggested in the initial comment.

// Retrieves all chats for the specified profile
Chat.allChatsByUser(uid).$loaded()
    .then(function(data) {
            var i = 0;
            var inProgress = false;
            while (i < data.length) {
                // A self-invoking function for handling async callbacks
                // Ensures that each iteration of the loop runs the async call

                // Wait for the last iteration to complete
                while(inProgress);

                // The function is starting now
                inProgess = true;
                (function(i) {
                        // Increment i within this scope
                        var item = data[i++];
                        // Function to sort users and chats from newest to oldest
                        // Matched user with item.$id = uid
                        Auth.getProfile(item.$id).$loaded()
                            .then(function(profile) {
                                    // Success case
                                    if (typeof profile === 'object') {
                                        if (chat.keyOrder == 'true') {

                                            // Retrieve the last chat from firebase
                                            // WAIT FOR THIS TO FINISH BEFORE PROCEEDING                       
                                            ref.child('chatting').child('messages').child(chat.chatId).on("value", function(data) {
                                                profile.lastChat = data.child('lastMsg').val();

                                                // Wait for the event
                                                // Adds chatting user's profile to the array
                                                chat.messages.push(profile);

                                                // Allow the next iteration to continue
                                                inProgess = false;
                                            });
                                        } else {
                                            // Handle invalid response
                                            return $q.reject(profile);
                                        }
                                    },
                                    function(profile) {
                                        // Promise rejection - End script
                                        return console.log('error', error);
                                    });
                                // Closing over i argument
                            })(i);
                }

Answer №2

Make sure to add chat.messages.push(profile) inside the value handler.

ref.child('chatting').child('messages').child(chat.chatId)
.on("value", function(data) {
  profile.lastChat = data.child('lastMsg').val();
  // append users profile to the chatting array
  chat.messages.push(profile);
});

Answer №3

If you're looking to handle this situation, I believe using the .all method is the way to go. Here's an example of how it can be implemented:

function fetchEvents(city, country) {

    return db.ref('countries').child(country).child(city).once('value').then(function(snapshot) {
        var eventPromises = [];
        snapshot.forEach(function(childSnapshot) {
            var eventId = childSnapshot.key();
            var eventPromise = db.ref('events').child(eventId).once('value').then(function(snap) {
                return snap.val();
            }, function(error) {
                console.error(error);
            });
            eventPromises.push(eventPromise);
        });
        return Promise.all(eventPromises);
    }, function (error) {
        console.error(error);
    }).then(function(data) {
        // Perform actions for each event
    });
}

Answer №4

Utilize the value event handler to add new entries to the array:

ref.child('chatting').child('messages').child(chat.chatId)
 .on("value", function(data) {
    profile.lastChat = data.child('lastMsg').val();

    // Add the chatting user's profile to the messages array
    chat.messages.push(profile); 
});

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

Is Formik Compatible with TextareaAutosize?

I've implemented react-textarea-autosize and formik in my project, but I'm having trouble connecting the change events of formik to TextareaAutosize. Can anyone guide me on how to do this properly? <Formik initialValues={{ ...

The switch statement remains unchanged for varying variables

Here is some code that I am working with: updateTable(selectedIndex) { console.log("running updateTable function"); let level = ''; // if (selectedIndex == 1){ // this.setState({level: 'day'}) // th ...

Stop or abort any pending API requests in Restangular

I am currently working with an API service: var SearchSuggestionApi = function (Restangular) { return { getSuggestion: function (keyword) { return Restangular.one('search').customGET(null, {keyword:keyword}); } }; }; SearchS ...

Encountering the issue of receiving an undefined value for a variable despite having previously defined it within

I’ve been working on implementing the Google Maps distance matrix API with the google-distance-matrix library. Here’s the code snippet I’m using: app.get("/users", (req, res) => { // console.log(req.query); // res.send(req.query); ...

The HTML and script tags are failing to connect

I recently started learning angularjs by watching the Egghead.io videos. However, I encountered an issue where I couldn't link my JavaScript page to my HTML page. my-index.html <!DOCTYPE html> <html> <head> <title>Angular ...

Regular expression that allows alphanumeric characters and spaces, but does not permit spaces at the beginning or end of the

I need to create a regular expression that allows for a combination of letters, numbers, and spaces within a word, ranging in length from 3 to 50 characters, but without spaces at the beginning or end of the string. Here is the regex pattern I have come up ...

What could be causing a parse error and missing authorization token in an AJAX request?

I recently wrote some code to connect a chat bot to Viber using the REST API. The main part of the code looks like this -: $.ajax({ url : url , dataType : "jsonp", type : 'POST', jsonpCallback: 'fn', headers: { 'X-Viber-Auth- ...

Angular Commandments: Understanding the Directives

Within my code, there is a specific directive view that I am utilizing: <div class="busy-indicator angular-animate" ng-show="busy"></div> <div class="breadcrumblist" ng-class="atTopLevel ? ['at-top-level'] : null"> <div ...

Is there a way to verify the functionality of a controller in an Angular directive?

Having trouble with testing the controller in my directive. I've tried searching everywhere, but it seems like when I attempt to call methods on my scope, they're nowhere to be found. I must be overlooking something obvious here, can anyone spot ...

Issue with scrolling to the bottom of collapsed sections in Bootstrap

I have a bootstrap collapse panel and I've added a toggle link at the bottom to allow users to expand and collapse the content with a click. The Issue My problem arises when the menu expands, causing it to scroll all the way to the bottom of the pag ...

Performing an HTTP request to itself in NodeJS/ExpressJS

Currently coding an NPM module that requires making an HTTP request to itself, which is the running web server. Here's an example: let url = "http://127.0.0.1:" + (process.env.PORT || 3000) + path; request(url, function(error, response, body){ ... ...

Is there a way to showcase a PHP code snippet within JavaScript?

This piece of code contains a script that creates a new div element with a class, adds content to it using PHP shortcode, and appends it to an Instagram section. Check out the image here <script> let myDiv = document.createElement("div"); ...

Don't pay attention to jquery.change

Consider the code snippet below: $(".someSelector").change(function() { // Do something // Call function // console.log('test') }); An issue arises where this code is triggered twice: once when focus is lo ...

Replace the phrase "add to cart" with "plus" and "minus" in Opencart

I am trying to customize the Add to Cart functionality in OpenCart 2.0.1.1 by replacing it with plus and minus buttons. I have successfully added the plus button, however, I am facing difficulty coding for the minus button. The code snippet below shows w ...

Issue encountered while importing dependency in Cypress Cucumber framework

Currently facing an issue with importing certain dependencies in Cucumber. The error message I received is as follows: Running: features\my_feature.feature... (1 of 1) Browserslist: caniuse-lite is outdated. P ...

Tips for accessing the value of the range slider in Bootstrap 5 while it is being slid

Is it possible to capture the value from a Bootstrap 5 slider while sliding? I want to continuously receive the value as I move the handle, rather than only getting the final value when I release the handle. Currently, I am using a Bootstrap 5 range slide ...

Steps for setting up node-openalpr on a Windows 10 system

While attempting to install npm i node-openalpr, an error is occurring: When using request for node-pre-gyp https download, I encounter a node-pre-gyp warning and error message. The package.json for node-openalpr is not node-pre-gyp ready, as certain pr ...

How come the CSS doesn't animate when I use JavaScript to switch the class?

I've implemented the Animate.css library by Daniel Eden, which I obtained from this source. Utilizing the animated (typeOfAnimation) class allows me to easily animate elements on my website. Below is a snippet of my HTML: <button onmouseover="mak ...

Integrate AngularJS service with Angular framework

Attempting to utilize the $log service within an angular 2 app, it seems that the following steps are necessary: Set up a module that includes the service you wish to inject. Utilize UpgradeAdapter's upgradeNg1Provider method. Therefore, I proceede ...

The React canvas within a CSS grid is not taking up the entire space

I'm currently developing a line plotter in React. This "line plotter" needs to be contained within a CSS grid item. I am utilizing the <canvas> element to draw the lines, but I'm unsure if this is the best approach. Is there a more efficien ...