Mastering Asynchronous Programming in JavaScript with Promises, .then() and .catch() methods, and Async/Await Syntax

Mastering Asynchronous Programming in JavaScript with Promises, .then() and .catch() methods, and Async/Await Syntax

Asynchronous and Synchronous nature

We listen very often that javascript is asynchronous. What does it mean? We know that JS is a web browser language and hence we cannot afford any delay in a site functioning if any of the middle processes takes a lot of time. And hence the asynchronous nature of JS comes into action in simple words, while running a JS code the functions which take more time in execution are kept aside while they finish and by that time the rest of the code keeps on running Once the part of the code that takes more time gives some output, it is then displayed.

Similarly, on the contrary, a synchronous function executes the code line by line and the whole script waits if any middle portion takes more time.

Since JS is an asynchronous language but sometimes in development processes we do require some part of the code to be executed synchronously and hence we need promises.

Promises in JS

Promise in JS is as simple as Promises in real life it tells whether a particular block of code is pending in execution or is executed or failed and returns a corresponding result in each of these cases.

Any code in JS can be wrapped under a promise or can be converted into a promise in two ways:-

  • Creating a new promise object of the Promise class

  • Using async/await keywords in functions or callbacks.

a. Creating a new promise object from the Promise class of JS:-

Creating a new promise object from the Promise class of JS is simple. By default, JS offers a Promise class in which we can make promises as objects. The promise object takes a callback which is two params reject and resolve, responsible for the failure and success result of the promise, respectively. These promise objects run directly as the code runs, and we can see their results by logging them. To get the promise states (pending, fulfilled, and rejected), we need to use methods such as .then() and .catch().

let promise = new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log("Hello")
      resolve("passed")                                                // the promise will resolve (get fulfilled) after 2 sec and its result would be  passed 
    },2000)
})

.then() and .catch() method

These are methods valid only on the block of code which return a promise.

.then() method generally takes two callbacks first to handle the fulfilled or successful execution of a promise while the second callback handles the error or the rejection state of a promise and returns some response instead of the error occurring in the block of code wrapped inside a promise.

But instead of using the second callback use often use the .catch() method

.catch() method is used in place of the second callback in the .then() method, it accepts a callback having the error as a parameter and it catches the error that occurred in a promise or an async block of code and due to this catching of error in the code out script doesn’t stops working after errors.

// .then() method runs when a promise is fulfilled 
// its first callback runs if promise is resolved and second callback runs (if exists) when a promise is rejected

// generally we do not use this method
promise.then((resolved_value)=>{
    console.log(resolved_value)  // will print passed 
},(error)=>{            // this callback handles the error
    console.log(error.message)
})


// usually we use .then() with one callback and .catch() for error
promise.then((resolved_value)=>{
    console.log(resolved_value)  
}).catch((error)=>{        // handles the error
    console.log(error.message)
})

b. Using async/await keywords in functions or callbacks:-

Using the promise or mainly .then() or .catch() method feels a little complicated or inconvenient to use. And hence we use this method as an alternative.

When we prefix any function or method with async, it converts that method or function into a promise. Then we can use .then() and .catch() with it while calling it. JS offers us another important feature called "await." Any promise when prefixed with await tells that async block of code to wait for that particular block of promise to be resolved first and then run the code further. In other words, it acts instead of the .then() method as both ways wait for the fulfillment of a promise and then do a particular task. Note that await can only be inside an async function or method. Also, to catch an error in the async await block, we use try-catch syntax, and hence we do not need .then() or .catch() methods.

// now this arrow function will return a promise
let fun1 = async () =>{   
   try{   
    console.log("start")
    const data = await fetch("<api_url>")    
    // fetch returns a promise by default and await stops the code                  untill promise from fetch is resolved
    console.log("end")
    }
    catch(error){    // handles any error in the fun1 promise
        console.log(error.message)
    }
}

fun1()

Conclusion

In conclusion, promises, .then() and .catch() methods, and async/await syntaxes are essential components of JavaScript, enabling developers to write efficient and robust code while maintaining a positive user experience.