How to Wait for a Function to Finish in JavaScript

Moataz Farid Feb 02, 2024
  1. Sync and Async in JavaScript
  2. Use callback to Wait for a Function to Finish in JavaScript
  3. Use promises to Wait for a Function to Finish in JavaScript
  4. Use async/await to Wait for a Function to Finish Before Continuing Execution
How to Wait for a Function to Finish in JavaScript

This tutorial will introduce JavaScript Callbacks, Promises, and Async/await and show you how to wait for an async function to finish before continuing the execution.

To understand what Promises and Async/await are, we first need to understand what the Sync and Async functions are in JavaScript.

Sync and Async in JavaScript

Synchronous programming executes one command at a time. When we call a function that performs a long-running action, it will stop the program until it finishes.

JavaScript is traditionally single-threaded, even with multi-cores. We can get it to run tasks only on a single thread called the main thread.

Such synchronous behavior is a limiting factor in the multi-threads but helps the user write codes without worrying about concurrency problems.

While in asynchronous programming, the long-running action will be executed in another thread other than the main thread, so the main execution is not blocked. When that long-running function finishes, the main program is informed and gets access to the results.

Most I/O primitives in JavaScript are non-blocking. Network requests, file systems operations are all non-blocking operations. Being blocked is the exception in JavaScript.

Since JavaScript is based on asynchronous programming techniques, there are multiple approaches such as callbacks, promises and async/await enabling you to put your functions executions in sequence. So that a code-block or a function won’t be executed before another specific function finishes.

sync and async

The above figure shows the clear variation between asynchronous and synchronous execution of two functions.

Use callback to Wait for a Function to Finish in JavaScript

If we have synchronous statements, then executing those statements after each other is straight forward.

function one() {
  console.log('I am function One');
}
function Two() {
  console.log('I am function Two');
}

one();
Two();

Output:

I am function One 
I am function Two

Suppose we want to execute two functions, functionOne() and functionTwo() such that functionOne() should be executed after executing some asynchronus statements inside functionTwo().

function functionOne(_callback) {
  // do some asynchronus work
  _callback();
}

function functionTwo() {
  // do some asynchronus work
  functionOne(() => {
    console.log('I am a callback');
  });
}

functionTwo();

When executing the above code, the last thing printed in the console is I am a callback. The famous callback example is the setTimeout function with a handler function to execute after timing out.

function testCallBack() {
  console.log('log before use setTimeout function');
  setTimeout(() => {
    console.log('inside timeout');
  }, 5000);
  console.log('log after use setTimeout function');
}

testCallBack();

Output:

log before use setTimeout function
log after use setTimeout function
inside timeout

Use promises to Wait for a Function to Finish in JavaScript

A promise is an object representing the eventual fulfillment or failure of an asynchronous operation. We attach the fulfillment callback to the promise with one or more then statements, and when can call the error handler callback in the catch.

doFirstThing()
    .then(result => doSecondThing(result))
    .then(newResult => doThirdThing(newResult))
    .then(finalResult => {
      console.log('The final result thing' + finalResult);
    })
    .catch(failureCallbackfunction);
}

To chain then and catch statements as the above example is one of the promises’ advantages. We promise to doSecondThing(result) once the doFirstThing() is fulfilled. The arguments to the then are optional, but required if you have to return a result.

In case there is an error, the browser will look at the end of the chain for the catch and execute it. It is very similar to the famous try-catch.

The following example will help us understand the promises chains and show us how we can wait for a function with asynchronous behavior to finish execution before we can continue execution.

var resolvedFlag = true;

let mypromise = function functionOne(testInput) {
  console.log('Entered function');
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('Inside the promise');
      if (resolvedFlag == true) {
        resolve('Resolved');
      } else {
        reject('Rejected')
      }
    }, 2000);
  });
};

mypromise()
    .then((res) => {console.log(`The function recieved with value ${res}`)})
    .catch((error) => {
      console.log(`Handling error as we received ${error}`);
    });

Output:

Entered function
Inside the promise
The function received with value Resolved

Creating a promise can be as easy as returning a new Promise(). The Promise() constructor receives a function as an argument, which should have two parameters - resolve and reject.

In case our event is fulfilled, and we need to return the result, we use the resolve() function when succeeding in what we were doing. But if an error happens and needs to be handled, we use reject() to send the error to the catch.

We set the flag resolvedFlag = true to simulate error handling in the catch. If resolvedFlag is set to be false, the reject() function is called, and the error is handled in the catch block.

Output:

Entered function
Inside the promise
Handling error as we received Rejected

Use async/await to Wait for a Function to Finish Before Continuing Execution

Another way to wait for a function to execute before continuing the execution in the asynchronous environment in JavaScript is to use async/wait.

The async function is the function that is declared by the async keyword, while only the await keyword is permitted inside the async function and used to suspend the progress inside the async function until the promise-based asynchronous operation is fulfilled or rejected.

The async and await keywords enable asynchronous, promise-based behavior in a cleaner style.

Let’s understand how async/await works. The function we are waiting for should return an instance of Promise class to wait for it to execute using the await keyword before calling it. As mentioned above, the function that contains the await statement must be declared with the async statement.

The following example shows how to wait for that promise-based function to finish before continuing the execution.

function testAsync() {
  return new Promise((resolve, reject) => {
    // here our function should be implemented
    setTimeout(() => {
      console.log('Hello from inside the testAsync function');
      resolve();
      ;
    }, 5000);
  });
}

async function callerFun() {
  console.log('Caller');
  await testAsync();
  console.log('After waiting');
}

callerFun();

Output:

Caller
Hello from inside the testAsync function
After waiting

Related Article - JavaScript Promises