Angular Async/Await: Why You Needed It & How To Use It

Svetloslav Novoselski / Monday, May 9, 2022

Angular is a great framework but writing asynchronous code and making asynchronous calls is hard. Especially if you can’t decide between Async/Awaitand AngularPromise. So, in this tutorial, I will help you understand the differences between Async/Await and Promise through examples and code snippets. I will also explain how you can easily avoid callback hell and I’ll demonstrate how to use Async/Await in JavaScript with the help of Ignite UI for Angular.

Here are the topics to be covered:

What Is Asynchronous Code in Angular?

When we talk about asynchronous code, we simply mean that the code isn't executed sequentially and the process involves multithreading. It is a form of parallel programming that executes a separate block of code without breaking the primary application thread. Running async code is useful in case of large iterations or when you have complex operations.

But if you aim at simplicity and short running operations for your Angular app, better avoid asynchronous programming. Usually, async code is more difficult to read, so anything that can improve its readability and make it simpler for developers is considered a quality booster. And JavaScript has its own tricks and mechanism to cope with this.

How JavaScript Handles Asynchronous Code

By default, JavaScript is a synchronous single threaded language, executing one statement at a time from top to bottom. This means that new threads and processes cannot run code in parallel to the main program flow. It has one call stack and one heap memory and executes code in order and must finish executing a piece of code before moving onto the next one. Everything happens sequentially. But what happens when, for example, you must make several AJAX calls in a single page?

The first solution that comes to mind is the use of callbacks. But they lead to a major problem known to programmers as “callback hell”. Essentially, this is a nested, promise-then code structure which requires the making of multiple requests and data transformations often resulting in difficult-to-maintain and read code and a less scalable app.

Turns out callbacks are not the best way to handle async code for your Angular app. What then? Perhaps Angular Promise? This pattern efficiently wraps asynchronous operations and notifies when they are complete. Yet, even though it delivers cleaner and more maintainable code, using Angular Promise isn’t the optimal solution as, quite often, it reuses the same code over and over again, contradicting the DRY (Don’t Repeat Yourself) principle.

Thankfully, we have Async/Await in Angular.

Using Async/Await in Angular

One of the best improvements in JavaScript is the Async/Await feature introduced in the ECMAScript 7. Basically, Async/Await works on top of Promise and allows you to write async code in a synchronous manner. It simplifies the code and makes the flow and logic more understandable.

Note that because it no longer uses then and catch chaining anymore, you can handle errors by running try/catch.

Async/Await vs Promise: What is the Difference?

To present the differences between Async/Await and promises, let’s make a table to compare them in a more digestible and concise way.

Promise 

Async/Await 

Promise is an operation which is guaranteed to complete its execution at some point in the future 

Async/Await is built on top of promises. They are syntactic sugar for promises, making the code look more synchronous 

Error handling is done using .then() and catch() methods 

Error handling is done using try() and catch() methods 

It could be difficult to understand promise chains  sometimes 

Async and await makes the code easier to read and understand the flow of the program  

It has 3 states – pending, resolved and rejected 

It returns a promise either resolved or rejected 

Let’s create one example with both syntaxes and see the differences. We have a function which is making two asynchronous calls to an API, one for getting user data and another to get clubs in which users are members. The second call is depending on the first one, which means getUserData() should be completed before proceeding with the other request. Both syntaxes are easy to read, but of course using promises with .then()  and .catch() can leads to callback hell, which makes the code tough to understand and maintain.

const makeRequest = () =>
     getUserData()
    . then(user => getClubsForUser(user.id))
    .then(console.log)
    .catch(err => console.log('Error: ' + err.message));
 

const makeRequest = async () => {
    try {
        let user = await getUserData();
        let clubs = await getClubsForUser(user.id);
        console.log(clubs);
     }
    catch(err) {
        console.log(err.message);
   }
};
 

How To Use Async/Await in Angular With Ignite UI

Let’s create a function which will get user data from a form input and then makes a request to an api to verify if the credentials for the user are correct and if so redirects to home page. Using Async/Await in Ignite UI for Angular can help us in this situation. We have a request to an API which is asynchronous operation and that’s why we will use await for it and then if there are no other problems to save the data.

const submitLoginData = async () => { 
    try { 
         if (this.userInput.email && this.userInput.password) { 
         const response = await this.loginUser(this.userInput); 

         if (response.statusCode === 200) { 
             alert('User is successfully logged in!'); 
             await saveUserData(response.data); 
             this.router.navigate(['/']); 
         } 
         else { 
             alert(response.message); 
             this.router.navigate(['/login']); 
         }
     } 
   } 
     .catch(err) { 
         alert('Something went wrong, try again later!') 
         this.router.navigate(['/login']); 
     } 
} 
 

We can definitely use .then() and .catch() here, but Async/Await in Ignite UI for Angular makes the code look more elegant. It’s up to the person who is writing the code to choose which syntax to use. But also, it is recommended sticking to one approach, as mixing styles can make the code complicated.

Async/Await Angular Best Practices

When we are using async and await to handle asynchronous code, we should always put our code into try/catch block. In this way we will ensure that even if the promise is throwing an error, it will be caught and processed properly.

async function loadComponents() {
     try {
         this.components = await fetchComponentsByType('charts');
     }
     .catch(err) {
         logger.error(err);
     }
}
 

With Ignite UI, we don’t need to explicitly return a promise in an async function. In fact, an async function always returns a Promise. Which means that creating a Promise inside an async function only adds performance overhead to our Angular app.

async function loadChartSelectors() {
     return Promise.resolve(['igx-data-chart', 'igx-pie-chart', 'igx-category-chart']);
}
 

Summary

Async/Await keywords make code easier to read and debug. However, if we want to use them correctly, we should understand how promises work in general, because as we said they are no more than syntactic sugar for promises.

Ignite UI for Angular