Wait For Loop to Finish in Node.js [SOLVED]

Loop actions can vary, and within the loop, there are different actions that we might work with. Some of these actions might be synchronous and some can be asynchronous.

For scenarios of asynchronous actions within loops (especially for loops), we need to make sure we allows them finish before we can move on to the next iteration.

Advertisement

In this article, we will detail how to wait for loop to finish in Node.js (JavaScript) using two methods.

 

Introducing Promises

Before we move into Promises, we need to discuss callbacks. Callbacks are functions passed to other functions and are executed when a specific code runs, so the functions that will be passed will have to finish their actions before being used by the other function.

A simple illustration can be seen below where we pass the help function as an argument of the cli function.

function help(tool) {
    console.log("The " + tool + " documentation is here thus");
}

function cli(callback) {
    let tool = prompt("Need Help? Enter Tool Name: ");
    console.log("Checking the database for the tool passed");
    callback(tool);
}

cli(help);

When we pass dgf within the prompt, our output becomes

Checking the database for the tool passed
The dgf documentation is here thus

JavaScript is asynchronous by nature so any long-running task will be queued, and will move on to other tasks. Therefore, with task such as networks calls, we can deal with undefined values using callbacks.

However, code with multiple callbacks can easily become messy and hard to maintain. This phenomenon is called callback hell. To deal with this, Promises are helpful and better to use.

Advertisement

The Promise object represents the eventual completion or failure of a JavaScript asynchronous operation and its resulting value, and it returns a Promise that will provide the resulting value when its needed within the code later.

To illustrate Promises, we can create a code that takes a URL and processes its response. The resolve deals for situation where the code succeeds, and the reject kicks in where the code fails.

function getData(url) {
    return new Promise((resolve, reject) => {
        if (!url) {
            reject("No URL provided");
        }

        const xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.send();
        xhr.onload = function () {
            if (xhr.status === 200) {
                resolve(xhr.responseText);
            } else {
                reject(xhr.status);
            }            

        };
    });
}

const url = prompt("Enter a URL");

getData(url)
    .then((result) => {
        console.log("Success!"); // Runs on success
        console.log(result);
    }).catch(status => {
        console.log(`An error with status code ${status} occurred: `); // Runs on error
    });

When we pass the https://reqres.in/api/users?page=2 as the input to the prompt, the output becomes

Success!
{"page":2,"per_page":6,"total":12,"total_pages":2,"data":
...

The .then() will be triggered when the getData function is successful, but the .catch() comes in when there is an error.

For our case scenario of dealing with waiting for loop to finish in Node.js, we will need this basic understanding of Promisies and asynchronous programming.

 

Using async/await to wait for loop to finish

With async/await keywords, we can enable Promise-based behaviour and asynchronous execution within our code. So, for use to wait for the loop to finish, we can define an async function and wait its result within.

Advertisement

 

Method 1: for...of loop

If we have iterables that we need to go over with a for loop but will need to carry out some asynchronous operations on (such as a network call), we can define our iteration using the below code

function wrap() {
    return new Promise((resolve) => setTimeout(resolve, 500));
}

async function logging(num) {
    await wrap();
    console.log(num);
}

async function printElement(array) {
    for (const num of array) {
        await logging(num);
    }
    console.log("Operation Completed.");
}

printElement([1, 2, 4]);

Output

1
2
4
Operation Completed.

The wrap() function holds the Promise object that will deal with the resolve situation within the code. Afterwards, we define an asynchronous function (logging) that logs the numbers we are iterating over but we await the wrap() function before logging the numbers.

From here, we define another asynchronous function (printElement) that will loop over the array and execute the logging function.

 

Method 2: Use Promise.all

Promise.all method takes an iterable of promises and returns a single Promise that will be fulfilled only when all the promises within it has been fulfilled. Since we have an iterable, we can make use of this method to initialize Promise for each, and then the method will return a Promise when all the Promises for each iteration has been fulfilled.

To achieve that, we can adjust the printElement function as thus by mapping the array to promises and waiting for all promises to be resolved before moving one.

Advertisement
async function printElement(array) {
    const promises = array.map(logging);
    await Promise.all(promises);
    console.log("Operation Completed.")
}

Output

1
2
4
Operation Completed

 

Summary

To wait for all operations within a loop iteration to finish, Promises are your best bet to dealing with such situations. Each method are effective in dealing with such, however, the Promise.all method which will run all the attached functions in parallel can make for a cumbersome approach in very large arrays.

 

References

Promise.all() - JavaScript | MDN (mozilla.org)
Promise - JavaScript | MDN (mozilla.org)

 

Didn't find what you were looking for? Perform a quick search across GoLinuxCloud

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can either use the comments section or contact me form.

Thank You for your support!!

Leave a Comment

X