Demystify Promises, Async, and Await in Javascript
A Promise is a special object which was introduced by ECMAScript in 2015.
Promises work on the concept of sticking to a commitment of providing needed data whenever requested by the consumer during further program execution.
If the commitment to provide data fails it returns it status as rejected and returns fulfilled if the data is properly returned.
The promises by default are executed asynchronously and reside in memory till they are processed by the CPU. The promise is the most useful and frequently used feature within Javascript.
If you take a look at Javascript libraries like React JS, the state functions are asynchronous and use promises to update the values.
How do Promises work
While creating a promise object an executor function will be passed to the constructor as a parameter and this function has two parameters, which are also the functions and they are resolve
and reject
.
- The
resolve
function is called it returns the data and marks the promised status as fulfilled. The data can be retrieved usingthen()
the method. - The
reject
the function will throw an error and mark the promised status as rejected. The rejection of promises can be handled outside the promise usingcatch()
method.
Why and When should we use Promise?
Promises are where created as a replacement for callback functions as error control needs to be separately added within the code.
unlike promises where errors can easily be handled. As the promise object is asynchronous we need to take the below-mentioned points into consideration before using promises.
- Using Promises keeps error control easily manageable as you don’t always and everywhere use exception handling to log errors.
- If you are aware that the function may or may behave asynchronously.
- If you don’t want program execution to wait till the data value is computed and you want to compute it in the background and then notify the user.
- Requesting of resources from external API. For most of the purposes, promises are used here example Fetch API, Axios, etc.
- If the requested task is not important and maybe call later when it is evaluated.
When you must not use Promise and prefer callbacks
You see if you want to synchronously get the data then you can use await
it within the async function. But the trade-off is that it makes that function asynchronous. Even though promises have largely replaced callbacks and most of the objects in Javascript use promises there are also a few good reasons I see where just using callback makes more sense.
- Cross-Browser Compatibility: If you are building web apps that you want to run on legacy browsers such as Internet Explorer, then reconsider your choice as these browsers have not yet added support for promises.
Note
However, you can use Promisify Polyfill Javascript library Promisify
- Performance: As Promises don’t execute instantaneously they occupy memory and if you are working on a complex module and you have created a lot of promises then your application performance may effect.
However, you’ll see the major effect on performance when you are working on large projects.
- Being Synchronous: If you want the execution of the code to only be synchronous. Then you may prefer not to use promises.
How to create a Promise Object
let simple_promise = new Promise( ( resolve, reject ) => { //body resolve( "pass data which needs to be returned" ) // marks promise as fullfilled reject( "pass error message or any other type" ) // marks promise as rejected and triggers catch method } )
Accessing Values within Promise
simple_promise.then( success_function, error_function )
Handling the rejection in Promise
The second function within .then()
is the error callback function which is optional and if you don’t want to specify and still log errors then use .catch()
the method at the end.
simple_promise.then( success_callback_function ).catch( e => "handle error here" )
Use Promise to return user information
let user_promise = new Promise( ( resolve, reject ) => { let user = { 'name' : 'Harry', 'designation' : 'Software Developer' } resolve( user ) } ) // accessing data returned by promise user_promise.then( (e) => { return {...e, salary : 150000 } } ) .then( e => console.log(e) ) .catch( ( e ) => console.log( e ) )
To return the values from a promise they must be passed within the resolve
function only then you can access them from .then()
method.
You can also evaluate those values, update them pass to the below .then()
method. Similarly, you can chain multiple such .then()
methods and perform different operations on them.
Using async and await with Promises
The keyword async
is declared before the function
. It lets that function handle promises in a synchronous way. For this an additional keyword await
must also be used before promise.
Note
You can use the await
keyword only if you declare the function with async
.
Example of Handling Promise based asynchronous functions handle synchronously
let num1=10, num2=20; let add_numbers = new Promise( ( resolve, reject ) => { resolve( num1+num2 ) } ); const display_result = async () => { let result = await add_numbers console.log( result) } display_result() //30
The await
makes promise to wait till its values are computed. You’ll see the evaluated value as 30 because we have passed it within resolve
the function.
Passing Extra Parameters within promise object
// using await const add_numbers = ( num1, num2 ) => { return new Promise( ( resolve, reject ) => { resolve( num1+num2 ) } ) } const display_result = async () => { let result = await add_numbers( 10, 25 ) console.log( result) // 35 } display_result()
The only way to pass additional parameters within promise is to use promise within function and return it.
Working with multiple promises
let eat_promise = new Promise( ( resolve, reject ) => { resolve( "Eating" ) } ) let sleep_promise = new Promise( ( resolve, reject ) => { resolve( "Sleeping" ) } ) const init = () => { console.log(1) eat_promise.then( d => console.log(d) ) console.log(2) sleep_promise.then( d => console.log(d) ) console.log(3 } init() /* output 1 2 3 4 Eating Sleeping */
Use await to synchronous process each promise
const init = async() => { console.log(1) await eat_promise.then( d => console.log(d) ) console.log(2) await sleep_promise.then( d => console.log(d) ) console.log(3) } /* output 1 Eating 2 Sleeping 3 */
Promise Static Methods
Promise.all( iterable )
The .all()
the method will be evaluated when all the promises get fulfilled. If anyone promise gets rejected then it calls .catch()
method.
let eat_promise = new Promise( ( resolve, reject ) => { resolve( "Eating" ) } ) let sleep_promise = new Promise( ( resolve, reject ) => { reject( "Sleeping" ) } ) const init = async() => { Promise.all( [ eat_promise, sleep_promise ] ).then( d => console.log( 'res', d ) ).catch( e => console.log( 'catch', e ) ) } init() /* Output catch Sleeping */
Promise.allSettled( iterable )
The .allSettled()
only check if all the promises are evaluated irrespective of fulfilled or rejected.
let eat_promise = new Promise( ( resolve, reject ) => { resolve( "Eating" ) } ) let sleep_promise = new Promise( ( resolve, reject ) => { reject( "Sleeping" ) } ) const init = async() => { Promise.allSettled( [ eat_promise, sleep_promise ] ).then( d => console.log( 'res', d ) ).catch( e => console.log( 'catch', e ) ) } init() /* Output [ { "status": "fulfilled", "value": "Eating" }, { "status": "rejected", "reason": "Sleeping" // if failed then reaso will be shown } ] */
This returns a list with objects which has the status of the promise and also the evaluated value. If a promise is rejected then instead of the value property reason
the property will be passed.
Promise.any( iterable )
The Promise executes if any one of the provided promises is fulfilled.
let eat_promise = new Promise( ( resolve, reject ) => { setTimeout( () => resolve( "Eating" ), 500 ) } ) let sleep_promise = new Promise( ( resolve, reject ) => { resolve( "Sleeping" ) } ) const init = async() => { Promise.any( [ eat_promise, sleep_promise ] ).then( d => console.log( 'res', d ) ).catch( e => console.log( 'catch', e ) ) } init() /* Output res Sleeping */
Note
If no promise gets fulfilled then AggregateError: All promises were rejected message is displayed.
Watch Video
Final Words
Promises are the new standards for building modern applications in Javascript. It also provides a lot of benefits when used properly and all the packages and Javascript objects are using promise. If you like my post then share it with your colleagues.