.then() vs await in JavaScript

In JavaScript, we use .then() and await to perform asynchronous execution of long-running tasks, such as making network requests to remote API or reading and writing data to and from a database server. JavaScript uses callbacks to handle asynchronous operations when we use .then(). Meanwhile, when we use await, it simply pauses the execution of the code until it receives a response.

JavaScript executes sequentially when we perform simple operations such as arithmetic operations or concatenating strings. In that case, the lines of code run one by one. We can demonstrate this behavior in the following code example:

let a = 4;
let b = 5;
let sum = a + b;
let concatenated = "Sum of " + a + " and " + b + " is: " + (sum) + ".";
console.log(concatenated);

In the example above, the code executes sequentially because each line returns its result immediately. When we start performing long-running tasks in JavaScript, we will not get a response to those requests immediately. Instead, we get a promise. In JavaScript, the promise is defined as:

The promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

We usually use either .then() or await to resolve these promises.

Using .then() to handle promises

Let's call the Advice Slip JSON API, a free API, to get random advice as a response. We will use fetch, JavaScript's built-in function, to make HTTP requests.

fetch('https://api.adviceslip.com/advice')
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log(error));
console.log("I will be executed before the lines above.")

Code explanation

Here is a line-by-line explanation of the code above:

  • Line 1: Calling the fetch function to make an HTTP request.

  • Line 2: Calling the .then() function to handle the HTTP response and convert the response to JSON.

  • Line 3: Calling the .then() function again to log the JSON response to the console.

  • Line 4: Calling the .catch function to handle any error that may occur (optional).

  • Line 5: Logging a simple text to the console.

After executing the code, we will notice that line 5 runs first before the lines above it because the synchronous feature of JavaScript allows it to continue the execution of other tasks while waiting for the completion of specific operations. Since the response of Advice API is not straight away and takes time to arrive, line 5 will execute before the result of Advice API. We also refer to it as the non-blocking behavior of JavaScript.

When working on a large-scale project, this type of code would make it difficult to manage. We need a way to resolve the promises sequentially or synchronously. The synchronous nature of JavaScript allows it to execute one operation at a time in the order they are defined.

Using await to handle promises

We resolve the promise synchronously by using await. We will achieve this by writing a simple function as follows:

async function getAdvice(){
let response = await fetch('https://api.adviceslip.com/advice');
let jsonResponse = await response.json();
console.log(jsonResponse);
}
getAdvice();
console.log("I will be executed after the lines above.")

Code explanation

Here is a line-by-line explanation of the code above:

  • Line 1: JavaScript requires us to write async keyword before a function that uses await.

  • Line 2: Calling the fetch function to make an HTTP request by prepending the await keyword.

  • Line 3: Convert the response to JSON by prepending the await keyword.

  • Line 4: Logging the response to the console.

  • Line 6: Calling the function.

  • Line 7: Logging a simple text to the console.

This time, we will notice that line 7 executes after the execution of the lines above it because we are now using await instead of .then().

We may wrap the function in a try-catch block to catch any possible error:

async function getAdvice(){
try{
let response = await fetch('https://api.adviceslip.com/advice');
let jsonResponse = await response.json();
console.log(jsonResponse);
}
catch(error){
console.log("Error: " + error);
}
}
getAdvice();
console.log("I will be executed after the lines above.")

It makes sense when we make an HTTP request and wait for its response before using it somewhere. The same thing happens in real life; for example, when we order food online, we cannot consume it immediately before it arrives. The restaurant from where we have ordered the food promises to deliver the food, and eventually, they will complete or fail that promise.

.then() vs. await

Let's make a quick comparison between .then() and await.

.then()

await

Results in out-of-order execution with complex chains.

Ensures sequential execution within an async function.

Requires using .catch() for error handling.

Uses try-catch blocks for error handling.

Widely supported across all modern JavaScript environments.

Introduced in ES8/ES2017, supported in modern environments.

Uses callbacks to handle asynchronous operations.

Pauses the execution until a response is received.

When to use one over the other

There are specific scenarios when using one over the other is preferred. Let's explore some use cases for both approaches.

.then() over await

Parallel execution: When we need to perform multiple asynchronous operations in parallel, .then() would be a better choice than await, since later will pause the execution while waiting for the response of a request. For example, if we need to call a weather API to get the current weather forecast and a food restaurant API to retrieve the food list, we can call these two API endpoints parallelly.

Handling streams of data: When working with data streams, choosing .then() over await will make sense. For example, if we receive a live video stream, displaying each chunk as it is received is more appropriate than waiting for the entire stream to finish.

await over .then()

Sequential execution: When working on a scenario where we want to execute an operation that depends on the result of a previous request, choosing await over .then() provides a synchronous-looking code structure. For example, when processing an order, we will process the payment and then the order.

Delays: When we need to limit the code execution of some code blocks, await provides a cleaner way to do that than .then(). For example, we can restrict the access to log in for a few minutes when a user performs failed login attempts.

Conclusion

JavaScript is synchronous but allows us to write code that executes asynchronously. Deciding between .then() or await is entirely based on the use case we are working on. While .then() is suitable for performing concurrent tasks, await is perfect for executing tasks sequentially.

Copyright ©2024 Educative, Inc. All rights reserved