Hey Guys, hope you are doing well, So today i am writing about async and await the most awaited feature for javascript ES7. For those of you coming from .Net or any other type of programming language you must be familiar with the async functions and await keyword. As of nodejs 7.6 async and await are now supported without any transpilation. Lets dive deeper into aysnc and await. and how to use them.
Async Functions
Async function makes your code looks synchronous will performing asynchronously. It is a syntactic sugar provided to us by Javascript ES7. Traditionally when dealing with asynchronous functions we used callback in which sometimes it creates a callback hell when working on a complex project. However to avoid callback hell and write more readable and less messy code we started using promises. If you don’t have an idea about promises you can check my blog about promises. Here is an example for callback hell.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function MakeMultipleCalls() { API1.Call(data,function(err,data){ API2.CALL(data,function (err,data2) { API3.CALL(data2,function (err,data3) { API4.CALL(data3,function (err,data4) { }) }) } ) }) } |
and following is an example for the same code written in promises.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function MakeMultipleCallsPromified() { API1.Call(data) .then(function (data2) { return API2.CALL(data2) }) .then(function (data3) { return API3.CALL(data3) }) .then(function (data4) { return API4.CALL(data4) }) } |
Now lets start with async and await.
Declaring Aysnc functions
await keyword can only be used inside an async function. so to declare an async function we simply put the async keyword before the function keyword when declaring a function.
1 2 3 |
async function myAsyncFunction() { } |
Once we declared our async function we will start using await keyword. Await Keyword works similar to generator function’s yield keyword. it holds the execution until the Promise or awaited expression is resolved. await doesn’t require a promise, even if an expression is given it will convert it into a promise.
1 2 3 4 5 6 7 8 9 10 |
async function myAsyncFunction() { try { let data = await myAPICall('https://jsonplaceholder.typicode.com/posts/1'); // It will not run this line until it resolves await. let result = 2 + 2; return data; }catch (ex){ return ex; } } |
Noticed we have wrapped the awaited call inside a try-catch block. It is because whenever promise rejects or there is some error resolving the awaited call it throws an exception which we can catch in the catch-block.
We can wrap multiple API calls in one awaited call like this.
1 2 3 4 5 6 7 8 9 10 11 12 |
async function MultipleAPICalls() { try { let myPosts = await Promise.all([ myAPICall('https://jsonplaceholder.typicode.com/posts/1'), myAPICall('https://jsonplaceholder.typicode.com/posts/2'), myAPICall('https://jsonplaceholder.typicode.com/posts/3') ]); return myPosts; }catch (ex){ return ex; } } |
Here we used Promise.all to call multiple APIs.
Isn’t It Synchronous code?
You might be confused by how the code looks as it looks synchronous and it might block the rest of your code. Well its not like that Async functions use promises behind the scenes hence they are asynchronous functions they return promise when called but lets not get into that just yet. Here i will show you a typical example for a promise and we will replicate it by async await.
1 2 3 4 5 6 7 8 |
function myPromiseAPI() { myAPICall('https://jsonplaceholder.typicode.com/posts/1') .then(function (data) { // The Code will execute once the promise is resolved. Which is independent to code outside the then function }); // Code that will run parallel to the promise making it a non blocking code. let result = 2 + 2; } |
A typical example of an API call with promises which makes a non blocking code. Now this is how we handle same scenario with async functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
async function myAsyncAPICall(){ try { // Trigger the API Call without await let ApiCallPromise = myAPICall('https://jsonplaceholder.typicode.com/posts/1'); // the code will not block. you can write your parallel code here let result = 2 + 2; // When you are done with your code... Wait for promise to resolve let data = await ApiCallPromise; // The Code will execute once the awaited call is resolved. Which is independent to other code }catch (ex){ return ex; } } |
Its not necessary to call await just when you want to do some asynchronous task. you can fire the asynchronous call and then await for it to resolve afterwards when you are done with all your other task. As show in above example. Here is a practical example we often use for multiple asynchronous calls.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
async function multipleAsyncAPICall(){ try { // Trigger the API Call without await let dataPromise1 = myAPICall('https://jsonplaceholder.typicode.com/posts/1'); // do you work... //.... // Trigger another API Call without await let dataPromise2 = myAPICall('https://jsonplaceholder.typicode.com/posts/2'); // do your work // ... // when done with your other independent code // Now await for both Promises let [data1,data2] = await Promise.all([dataPromise1,dataPromise2]); }catch (ex){ return ex; } } |
Now as i mentioned earlier async functions are non blocking code. That means everything other then the function will not be blocked. As async functions can be used as a promise or can be awaited in other async functions.
Here is an example of async function being awaited in another async function.
1 2 3 4 5 6 7 8 |
async function otherAsyncFunction (req, res) { try { let data = await myAsyncFunction() return data; }catch (ex){ return ex; } } |
As i mentioned earlier that async function returns promises so we can also use them with .then() function.
1 2 3 4 5 6 7 8 |
async function otherAsyncFunction(req, res) { myAsyncFunction() .then(function (data) { return data; }).catch(function (err) { return err; }) } |
Noticed here instead of using try-catch-block. I used .catch() methods to handle the error and promise rejections because rejected promises or error thrown by promises are caught in .catch() method.
Last but not least !
You can use async functions with express routes. It does support async functions so we can use it to await for any type of promise whether a DB call or an I/O operation or anything else in the APIs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
router.route('/asyncmethod') .get(async function (req, res) { try { myAsyncFunction() .then(function (data) { console.log("my work",data); res.send(data); }).catch(function (err) { res.send(err); }) }catch (ex){ console.log('whaat',ex); res.send(ex); } }); |
Conclusion
Async await is a great feature that finally shipped with node.js 7.6. That are so many practical use-cases for this new feature. I have given you a taste of how powerful feature it is. and I encourage you to use it effectively in your projects. I have uploaded the entire source code for this project onto my github. You can clone it fork it or download it here.
Until next time then, Hope you all have a Good day or night 🙂