To achieve this functionality, we will end up with many nested callbacks known as callback hell. Luckily JS involved from callbacks to promises(ES2015) and then further to a more straightforward format of async/await (ES2017).
The purpose of async / await is to simplify the code syntax necessary to consume the promise returned by an API.
Here the parameters are:
- name Optional:
The name of the async function. (fun1)
- param Optional:
They are the name of the arguments that are passed to the async function. (param0)
- statements Optional:
This promise will be either resolved with the value returned by the function or rejected with a thrown exception from within the async function, which will depend on the conditions.
The main purpose of async/ await functions is to simplify the syntax of promises when they (promise) are used synchronously. It is similar to the combination of promise and generator.
Let us suppose we wish to have some tomato juice made at home, but there are a few steps to be followed:
- We need to buy some tomatoes from the market.
- We need to peel the tomatoes.
- We need to add it to a juicer to make the juice.
Code using async await:
- In the case of API calls, fetching data from the database or any information from the server.
- In the case of using the timeouts functionality.
- Increasing the responsiveness and performance of the application in case of extended running programs.
- Organizing the code to look clean and readable.
Async/Await is just syntactic sugar for promises.
Explanation and working of the above code in depth:
- Foremost, a console.log() is encountered by the engine at line 11. It gets added to the main call stack after which Before function! gets logged into the console.
- Then myfunc() is called and hence it is pushed onto the main call stack, after this the function starts its execution. Here the engine encounters the second console.log() on line 6, which gets popped onto the main call stack, after which Before function! gets logged into the console and the function gets popped from the call stack.
- Now the engine jumps out of the async function and continues the execution of the code in the caller function. Here the engine encounters another console.log() on line 14 which gets popped into the main call stack, after which After function! gets logged into the console. Finally, the call stack is empty, and hence event loop checks to see if there are any pending tasks in the microtasks queue for execution.
- myfunc() again gets popped into the call stack and continues its execution where it earlier left off. The variable res gets its value from the resolved promise from doSomething(), another console.log() on line 8 is popped onto the stack, Something is printed in the console, and the async function is popped from the call stack.
There are two types of queues to manage async behavior, a micro task queue which can only contain process.nextTick(), async, and promise callbacks; second is a microtask queue which can only contain setTimeout(), setInterval(), and setImmediate().
Async Functions and Execution Order
In the above example, the sequential execution starts instantly and reaches line 17; after that, execution gets suspended for 2 seconds until the first function is resolved. After that, there is another delay of 1 second for the second function to resolve. So in total, the code takes 3 seconds to execute.
Rewriting a Promise Chain with an Async Function
Real-world example of Promise chaining of food order:
Now to convert it into async await we can follow the following steps:
- Conversion of .then() calls to await:
In the classic promise syntax, the promise was resolved using the .then() function and was rejected using the .catch() keyword. But in the new async await format, the function will be called using the await operator, which halts the execution of the current function until the called function is settled.
- Using async keyword:
All the function that uses await must be followed by the async keyword.
- Error handling using the try-catch block:
We will wrap the entire code in a try block and then catch errors if any.
Promise chain migrated to async await format code of the above example of food order:
This format of async awaits benefits over Promise Chains because of simple and flexible code, easy chaining, Efficient error handling, and no nesting of callbacks; hence layout is simplified.
Async function js statements are supported in the following browser version:
- Async functions are generally a combination of generators and promises, basically syntactic sugar for promises.
- The async/await is a very useful tool for writing clean code hence helping in avoiding callback hells.
- When a function is prefixed with async, then the function always returns a promise which can be handled by the await keyword.
- Even if the function is not returning a promise explicitly, the engine will internally make the function return a promise.
- Await returns the resultant value when the promise is resolved, and if the promise is rejected, the await operator throws the rejected value.
- Await operator can only be used inside an async function.
- Async await provides us with a way to migrate from promise chaining and maintain a readable and more manageable code using await expression and a try-catch block.