Async JS : callback to promise

Akash PramodAkash Pramod
9 min read

Hello my coding friends ! How are you ? Are you enjoying the coding in JS ? Ummm, Yes or No ? Are you stuck ? Where ? Let me think ummm, asynchronous callbacks and promises, right ? Don't worry , it's not a big thing. Every beginner stuck in this part of asynchronous. There are more then 90 % JavaScript coder who doesn't understand asynchronous callbacks and promises in one go, I was also in list of those 90%. So here we will discuss from scratch to learn everything about callbacks and promises.

So, from where we have to start ? callbacks or promises ? Not from both. We will start from basic of JS. Yes, exactly. I know , you know JS basic very well. But even that we will start from JS basic. We will discuss here everything which is necessary to understand about callbacks and promise.

Understanding of synchronous JS :

JS is a single threaded language , which means that it can run only one line of code at a time. It waits the completion of previous line of code to execute the next line of code, it stops the whole program till previous work is done. It makes JS a problematic when we have to run a piece of program which takes time to complete, but because of JS nature it stops the whole program. But we have to do multiple things simultaneously, like reading file, fetching data and want to execute a piece of code with some delay, then JS fails to do this because of JS nature.

Let's understand this by an example. Imagine you invited your friends at your birthday party. And after they reached , you told them , hey friends just sit in drwaing hall but you don't have to do anything till I bring water or snacks for you. Now you took few minutes to bring all things and your friends are still waiting. Now you tell me there is any reason just to sit at one place without doing anything ? No, right ! They could do multiple things, but order them just to sit. And that is the nature of JavaScript.

Understanding of asynchronous JS :

Now to solve the synchronous nature of JavaScript , asynchronous came into the game. And it the creates a new feature of JS with asynchronous in which any line of code who is taking some time , they allowed the next line of code to run and execute while time taking code is working behind the curtain simultaneously. When we are reading a file or fetching any data which takes some time, we do this in async code so that it will not block next line of code till it's done.

Lets take the last example again. You invited your friends at your birthday party and when they reached, you told them sit in drawing hall and do whatever you want I brings water and some snacks for you. Then what will happen ? Till the time you are taking to bring snacks for your friends , you friends are doing other things like decorate you room , start the music , and may be some friends will start dancing. Your friends doesn't need to wait till you come back. And that is Asynchronous JS.

Synchronous JS is blocking code execution in nature but asynchronous JS is non-blocking code execution.

Example Of synchronous JS :

// Below Codes will run one by one after completion of previous code because of JS nature, synchronously: 
console.log("ONE");
console.log("TWO");
console.log("THREE");

Example of asynchronous JS :

// The code given below will execute asynchronously: 
console.log("ONE"); // first this code will execute
setTimeout(() => {console.log("TWO")}, 2000); // this will execute after 2 seconds but till next line doesn't have to wait too execute, will execute this line at last
console.log("THREE"); // second this line will execute

Now you don't need to understand about setTimeout(). we will discuss about this later. Here just understand that when we want to run a piece of code to execute with some delay, we use setTimeout() by passing time in milliseconds in it.

TO MAKE CODE ASYNCHRONOUS WE USE CALLBACKS, PROMISES AND ASYNC/AWAIT. BUT HERE WE WILL DISCUSS ABOUT CALLBACKS AND PROMISE ONLY.

CALLBACKS :

What is callback ? Callback is itself a function. It's just a function which called callback when we pass it as an argument to the other function or it return from another function.

Callback’s Example :

function callbackExample(array, callbackFunc){
    let evenNumbers = [];
    for(let i = 0; i < array.length, i++){
        evenNumbers.push(callbackFunc(array[i]));
    };
    return evenNumbers;
};

function callBack(number){
    if(number % 2 === 0){
        return number;
    };
};

console.log(callbackExample([1,2,3,4], callBack));

To achieve the asynchronous behavior we use callback. Using callbacks we can perform any type of asynchronous operation. When we perform an asynchronous operation, the program doesn't wait for that operation to complete. Instead, it immediately moves to the next task, and the result of the async operation is provided later by a callback function.

Callback is most famous and easy way to make code asynchronous but can be lead to "callback hell"(will discuss ahead) if nested callback is available.

Why we need callbacks ?

As we know JS is a synchronous language , we use callback to get the asynchronous behavior. If we running any time taking task then using callback we can run this code with next lines of code simultaneously. This is the most easy way and become worst when it perform nesting.

Without callbacks : If we read any file or any time taking task then synchronously then it will wait to complete this task first then will execute next line of code.

console.log("File Reading Started")
const data = fs.readFileSync('file.js', "utf8");
console.log(data);
console.log('File Reading Done');

The above code will execute each line one by one and wait till file reading work is going on. It will not execute third line till previous work is not done even it will take so much time.

With Callbacks : callback with asynchronous always come with success or failure. For example if a code is reading the file then there can be two things happen, one file reading is done means success and another file reading is not completed by any xyz reason means failure.

console.log("File Reading Started")
const data = fs.readFile('file.js', "utf8", (error, data) => {
    if(error){
        console.error("Error: ", error);
    }else{
        console.log(data);
    };
});
console.log(data);
console.log('File Reading Done');

In above code program will execute first line of code then will run second line of and start reading the file but it don’t stop the next line of code it gives the permission to execute the next lines of code simultaneously while "reading file" is running behind the curtain. So the execution will be : first line, last line and then after file reading will execute and print data.

Callback Hell : callback hell is a situation where multiple nested callback make code reading and maintain difficulty. When code started going horizontally it makes code difficult to read, maintain and debug. That is called callback hell. When input of one function depends on output of another function then we have to use callbacks and it makes code nested and if nesting is deep it creates callback hell.

Example of callback hell :

console.log("Pragram Started");

setTimeout(() => {
    console.log("First Task");

    setTimeout(() => {
        console.log("Second Task");

        setTimeout(() => {
            console.log("Second Task");

            setTimeout(() => {
                console.log("Second Task");

                setTimeout(() => {
                    console.log("Second Task");

                    setTimeout(() => {
                        console.log("Second Task");
                    }, 2000);
                }, 2000);
            }, 2000);
        }, 2000);
    }, 2000);
}, 2000);

The above code is the example of callback hell. where one callback depends on previous callback. It becomes difficult to read, maintain and debug the code.

PROMISE :

Promise is an object of asynchronous JS which gives the result of completion of a work as success or failure. There are three state in promise : pending, resolve, reject.

  • pending : when promise if not fulfilled nor reject.

  • resolve : when promise is served means fulfilled.

  • reject : when promise is reject or no served.

Understanding promise with example : Just imagine you order some food an online food app. After payment you have to wait to get the food or food rejected by the app , this is called pending state where you have to wait regardless of completion of the task , it can be served or rejected. But when you got your order that is call resolved means promise is fulfilled and if your food is rejected then it will be in reject state where your order is rejected. After the completion of the promise either be resolved or reject, this state is called promise settled.

What is the use of promise ?

It is solved the callback hell problem . Before promise callback hell makes code not readable with difficult to maintain and debug the code. But after promise, now code is easy to understand and debug.

We can create promise by promise constructor with new keyword and a callback function and in this callback function two another method is passed resolve and reject which is already defined. We can pass only resolve method but can't pass reject only.

const promise = new Promise((resolve, reject) => {
    const number = 20;

    if(number === 20){
        resolve(number);
    }else{
        reject("Error");
    };
});

In above promise code, promise returns success or failure of the task. If it's rejected then reject will handle the error and if it success then resolve will handle this data then you can handle both error and data according to your requirement.

Now after defining promise it doesn't work without using .then() and .catch(). Both take callback as a parameter. .then() is used when task is success and .catch() is used when promise got any error. for doing this we use promise.

promise
    .then((data) => {
        console.log(data);
    })
    .catch((error) => {
        console.error(error);
    });

Here we can use promise as the solution of callback hell. In callback hell, there is nested callback but in promise we have promise chaining.

when we use output of one .then() as input of next .then() then it will become promise chaining. .catch() always goes at last of .then() and before .finally().

.finally() is just a wrap-up code which will execute regardless of resolve and rejection.

promise
    .then((data) => {
        console.log(data);
        return data + 10;
    })
    .then((data) => {
        console.log(data);
        return data + 29;
    })
    .then((data) => {
        console.log(data);
        return data + 20;
    })
    .catch((error) => {
        console.error(error);
    })
    .finally((data) => {
        console.log("Got the error or data");
    });

So friends we have completed callback and promise very well . If you still have any doubt or any question, feel free to ask to me. We will meet again with another topic.

Happy Learning, Happy Coding.

0
Subscribe to my newsletter

Read articles from Akash Pramod directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Akash Pramod
Akash Pramod