Promise based asynchronous code in JavaScript has typically not been the easiest to write. Dealing with promise-chaining and nested callbacks can sometimes cause code to be difficult read, which could result in increased bugs down the line.
The 'async' and 'await' keywords are relatively new additions to the JavaScript specification first appearing in ECMAScript 2017. Their job is to essentially make writing asynchronous code easier and more in line with traditional synchronous code.
The first part to discuss is the async identifier that prefixes any function you wish to make asynchronous.
The 'async' keyword
Adding the 'async' prefix to a function declaration effectively turns the function into an asynchronous function. Asynchronous functions effectively always return a Promise back as the return value.
Async functions can be declared without the need to include any await caller. More on that below. But first, here is an example of the syntactical use of async.
async function func1(){
return 1;
}
With the traditional promise based syntax, the same code would look like the following:
function func1(){
return Promise.resolve(1);
}
Both methods above would do exactly the same. In both cases however, each method is returning a Promise back to the caller, not the actual value itself. That means that we'll have to extract the actual resolved value using a .then() block.
func1().then(result => console.log(result));
Creating an asynchronous function
The 'await' keyword
The 'await' keyword is the second half the async/await asynchronous duo. It must be placed inside of a function that is identified as 'async'. The 'await' keyword before a function call ensures that the function being called returns a Promise back to the caller before any other code is executed.
async function func1(){
let result = await Promise.resolve(1);
console.log('A');
return result;
}
The await keyword can be placed in front of any asynchronous function that returns a Promise and will essentially pause the code until the resulting promise has been completed.
You can include as many await function calls as you need in your async functions.
Adding error handling
While you can use a synchronous try/catch block in your asynchronous code, like the following:
async function func1(){
try{
return Promise.resolve(1);
}
catch(error){
// log error
}
}
You can also offload error catching to outside of the function declaration and into the function caller using a .catch() block.
async function func1(){
return await Promise.resolve(1);
}
func1().then(res => console.log(res)).catch(error => console.log(error));
The biggest benefit here is that the new .catch() block will catch errors in both the asynchronous function and the attached .then() block as well. In the end you end up with cleaner and easier to read and debug code.
When to use it
Just as you don't want every function to be synchronous, you also don't need every function to be asynchronous.
The answer of 'when do I use this?' will mainly come down to the current scenario that you find yourself in.
If you have a scenario where you require the data from one function call in order to pass the data into another function, then using the async/await pattern can be the fastest method to do so.
And if you are already using the traditional Promise object approach, then you can begin to slowly convert your code towards async/await as both methods rely on promises.
Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.
Last updated on:
Have a question on this article?
You can leave me a question on this particular article (or any other really).
Ask a question