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.
.then()
to handle promisesLet'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.")
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.
await
to handle promisesWe 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.")
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 | Uses |
Widely supported across all modern JavaScript environments. | Introduced in |
Uses callbacks to handle asynchronous operations. | Pauses the execution until a response is received. |
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.
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.