The only time your JavaScript code doesn’t wait for a loop to finish is when you’re working with Promises.

A good example would be email sending like this:

function sendAllEmails() {
  for (email of emails) {
    sendEmail(email);
  }
  doSomethingElse();
}

Here the function doSomethingElse() is going to run before any of the emails actually finished sending.

Sequential Solution

First way we can do this is by sending the next email only after the previous email was sent. In short, we wait for one function to complete before running another loop:

async function sendAllEmails() {
  for (email of emails) {
    await sendEmail(email);
  }
  doSomethingElse();
}

Here the function doSomethingElse() runs only after the last email was successfully sent. But you need to be aware that if you have thousands of emails to send and even if it takes 1 second per email – you will wait about 16 minutes per 1000 emails.

Concurrent Solution

Second way initiates sending of the next email even before the previous email was delivered. But the function doSomethingElse() is not triggered until every last email was successfully sent.

async function sendAllEmails() {
  const allEmailPromises =
    emails.map(email => sendEmail(email));
  await Promise.all(allEmailPromises);
  doSomethingElse();
}

The difference here is that even if you have 1000 emails and it takes 1 second per email – you will only wait 1-2 seconds before all emails were successfully sent. And then the function doSomethingElse() will be called.

P.S. -> read this article if you want to double your salary as a programmer