Definition of async-await
Creating a function with the async function
statement will define an asynchronous function. When an async function is called, it will return a Promise
. When the async function returns the value, the Promise will be resolved with the newly returned value. When the async function returns an exception, the Promise will be rejected.
The async function may include the await
expression, which will suspend the execution of the async function and wait until the Promise is done to continue the async function. The await keyword is only valid within the async function. If you use it outside the async function body, you will get a SyntaxError.
Simply put, it is an opportunity for the code to be asynchronous in a synchronized fashion.
Example 1
Let's start with a simple example. A function to return the Promise will resolve after 2 seconds, and return the value as the variable passed.
1 2 3 4 5 6 7 8 | resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } |
For promise
, we can use the return value using the then()
callback function then()
1 2 3 4 5 6 7 | getValueWithPromise() { this.resolveAfter2Seconds(20).then(value => { console.log(`promise result: ${value}`); }); console.log('I will not wait until promise is resolved'); } |
In this case, console.log()
on line 5 will be printed before console.log()
on line 3, which is the nature of promise
.
Now let's see how async-await works:
1 2 3 4 5 | async getValueWithAsync() { const value = <number>await this.resolveAfter2Seconds(20); console.log(`async result: ${value}`); } |
A few points to note
- Line 1 – The function starts with
async
keyword, this keyword is required ifawait
used in your function. - Line 2 – We do not call
then()
after the promise, instead we will add theawait
key in front. This keyword will not allow the next line of code to be executed, meaningconsole.log()
in line 3 is only called when the promise in line 2 is resolved, just like when handling a synchronous function. - Because we use Typescript, we need to enter the return data type of the promise, as in the above example,
<number>
.
Example 2
1 2 3 4 5 6 7 8 9 10 11 | addWithPromise() { this.resolveAfter2Seconds(20).then(data1 => { let result1 = <number>data1; this.resolveAfter2Seconds(30).then(data2 => { let result2 = <number>data2; this.additionPromiseResult = result1 + result2; console.log(`promise result: ${this.additionPromiseResult}`); }); }); } |
In fact, ending in nested promises is very common (or callback hell), as in the above example we have two nested levels. But try to imagine with 7 or 8 nested floors, along with variables and exceptions, how scary it will look.
With async it will look like this:
1 2 3 4 5 6 7 | async addWithAsync() { const result1 = <number>await this.resolveAfter2Seconds(20); const result2 = <number>await this.resolveAfter2Seconds(30); this.additionAsyncResult = result1 + result2; console.log(`async result: ${this.additionAsyncResult}`); } |
A glance at it also makes it much simpler. Although it returns the same results, in terms of readability and maintainability, async-await is superior to the use of classic promises.
Use Http REST APIs
In Angular application, we can get data through Http or HttpClient service. By default, HttpClient methods like get()
, put()
, delete()
, post()
return Observable<T>
. This result can be used via the subscribe
method or the toPromise()
operator from RxJs.
Get the HttpClient result using Observable
Many Angular devs use subcribe
to get HTTP Rest data without even knowing how it differs from promise
. The subscribe
method will be taken from an Observable
object. Once subscribe (registered), callback subscribe
will be executed every time a new data generated by the Observer
. Meanwhile, the promise callback then()
will only be executed at most once. So unless you absolutely need to retrieve recurring data, don't subscribe
. Instead, use toPromise()
. If you pay attention to the examples in Angular's documentation, they are mostly used toPromise
.
1 2 3 4 5 6 7 8 | getDataUsingSubscribe() { this.httpClient.get<Employee>(this.url).subscribe(data => { this.subscribeResult = data; console.log('Subscribe executed.') }); console.log('I will not wait until subscribe is executed..'); } |
Get HTTPClient result using toPromise:
Rx.js provides a method called toPromise()
, and we can use it to convert a Observable<T>
into a promise. Once converted, the content within its then
will be called whenever new data is available.
1 2 3 4 5 6 7 8 | getDataUsingPromise() { this.httpClient.get<Employee>(this.url).toPromise().then(data => { this.promiseResult = data; console.log('Promise resolved.') }); console.log('I will not wait until promise is resolved..'); } |
Get HTTPClient result using Async-Await
With Async-await syntax, we do not need to use both subscribe
and toPromise
. The code then looks very simple and intuitive. In the example below, the third line will be executed once the data is fetched from the "url", Observable <T> is converted to promises, promises are resolved, and the data will be stored in the asyncResult
variable.
1 2 3 4 5 | async getAsyncData() { this.asyncResult = await this.httpClient.get<Employee>(this.url).toPromise(); console.log('No issues, I will wait until promise is resolved..'); } |
Conditional programming:
A common case is that the program will need to retrieve data from a url, then consider the condition to fetch the next data. Using promises, the code will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 | getConditionalDataUsingPromise() { this.httpClient.get<Employee>(this.url).toPromise().then(data => { console.log('First Promise resolved.') if (data.id > 5) { let anotherUrl = 'http://dummy.restapiexample.com/api/v1/employee/23'; this.httpClient.get<Employee>(anotherUrl).toPromise().then(data => { this.conditionalPromiseResult = data; console.log('Second Promise resolved.') }); } }); } |
Instead, if using async-await, the code would look like this:
1 2 3 4 5 6 7 8 9 | async getConditionalDataUsingAsync() { let data = await this.httpClient.get<Employee>(this.url).toPromise(); if (data.id > 5) { let anotherUrl = 'http://dummy.restapiexample.com/api/v1/employee/23'; this.conditionalAsyncResult = await this.httpClient.get<Employee>(anotherUrl).toPromise(); } console.log('No issues, I will wait until promise is resolved..'); } |
In general, async-await provides a better way to handle asynchronous applications in Angular applications.
Source: https://medium.com/@balramchavan/using-async-await-feature-in-angular-587dd56fdc77