In this post, we will see what are callbacks and promises in JavaScript explained with the help of examples.
What are callbacks?
Callbacks are functions that are passed inside the arguments of other functions, this procedure is valid in JavaScript because functions are objects and objects can be passed as arguments to functions. The basic structure of the callback function looks something like this.
callback();
}
Execution sequence and need for callbacks
Callbacks functions are used to acquire control over the sequence of execution. Generally, functions are executed on the basis of the sequence that they are invoked, not on the sequence in which they are defined. For example:
console.log("I am task 1");
}
function job3() {
console.log("I am task 3");
}
function job2() {
console.log("I am task 2");
}
job1();
job2();
job3();
You would get the following output:
But what if we want to invoke task 2 only when task 1 finishes its processing. For that, we need callback functions and some basic understanding of asynchronous execution.
An example of callback in action
Consider the following code:
function addNewMember(newUser) {
members.push(newUser);
}
function getAllMembers() {
console.log(members);
}
addNewMember("Alpha");
getAllMembers();
We are working with an array that contains the list of members of a social club, and we have two functions. One function that prints out the list of all the members and the other one is used to add a member to the list.
Let’s change this code to make it mimic the behaviour of real databases and networking delays like lag and pings.
function addNewMember(newUser) {
setTimeout(function () {
members.push(newUser);
console.log("Member Added");
}, 200);
}
function getAllMembers() {
setTimeout(function () {
console.log("Members are:");
console.log(members);
}, 100);
}
addNewMember("Alpha");
getAllMembers();
As you can see, this code is using the setTimeout() function to mimic delays of databases. The addUser takes about 2 seconds and getAllMembers() function takes 1 second.
We want to add a new user “Alpha” and print the list after the member is added, not before and that is why we use the sequence:
getAllMembers();
Run the code and you will get the following output:
The list was printed first, and then the member was added. This is because the program did not wait for the addMember() function to finish processing. Now if we use callback functions to execute the getAllMembers() function only after the addNewMember() is finished, our code becomes:
function addNewMember(newUser, callback) {
setTimeout(function () {
members.push(newUser);
console.log("Member Added");
callback();
}, 200);
}
function getAllMembers() {
setTimeout(function () {
console.log("Members are:");
console.log(members);
}, 100);
}
addNewMember("Alpha", getAllMembers);
If you look at the code, you will see that inside the addNewMember() function we are taking a callback argument, this will ensure that the callback function will be executed in our desired sequence.
The output of the above code snippet is as:
The new member was added first and then the whole list was printed onto the console. That is how you can use callbacks to gain control of the sequence of execution.
What are promises?
A promise is an object and is something that is done/completed in the future. In JavaScript, it is exactly the same as in real life. The syntax of a promise in JavaScript is given below:
// some code
});
As can be seen from the Promise syntax, the promise constructor only accepts the callback function as an argument. The resolve and reject parameters are used in the callback function, with resolve being called when the activities conducted inside the callback function are successful. If the procedure is unsuccessful, however, rejection is called.
For example, let’s suppose your mother promises you to get you a bicycle on your birthday. That promise is her guarantee that she will buy you a bicycle on your birthday however when the time comes she can change her mind. So she can buy you a bicycle or not. This is a promise in simple layman language. Looking at this example we can identify three states/ possibilities of a promise in Javascript:
- Fulfilled: bicycle is bought. Result value
- Pending: your birthday has not come and you are not sure whether your mother will buy you a bicycle or not. Undefined
- Rejected: Bicycles are not bought for you on your birthday. Error.
To better understand Promises let us go through an example:
We will take this example step by step i-e first we will create a promise object using the Promise constructor as seen in the syntax of promise above. Next, we will use that promise object.
In the below code we will create a promise object:
var myPromise = new Promise(function(resolve, reject) {
const number1 = 2;
const number2 = 2;
// comparing two numbers
if(number1 === number2) {
// Operation successful
resolve();
} else {
// Error occurred
reject();
}
});
In the above code, first, we created a promise object myPromise, and then passed a callback function inside the Promise constructor. In the function, we are checking whether two numbers are equal or not. If the numbers are equal, the call will be resolved, otherwise if an error comes then the call will be rejected.
To use the promise object (myPromise) we will need “promise consumers” (consume Promises by registering functions) known as then() method for fulfilment and catch() method for rejection. The below code illustrates this:
then(function () {
console.log("Numbers Equal. Success");
}).
catch(function () {
console.log('Error');
});
If the numbers that are being checked are equal then the .then() method will be invoked and we will see “Numbers Equal. Success”. However, if the numbers are not equal then the .catch() method will be invoked and we will see the Error message in the console window.
The whole code is given below:
var myPromise = new Promise(function(resolve, reject) {
const number1 = 2;
const number2 = 2;
// comparing two numbers
if(number1 === number2) {
// Operation successful
resolve();
} else {
// Error occurred
reject();
}
});
// Use Promise object
myPromise.
then(function () {
console.log("Numbers Equal. Success");
}).
catch(function () {
console.log('Error');
});
From the output, we can see that the numbers are equal.
Conclusion
To implement asynchronous code in JavaScript we use callback functions and promises. A callback function is passed as an argument to another function whereas Promise is something that is achieved or completed in the future. In JavaScript, a promise is an object and we use the promise constructor to initialize a promise. To use promise objects we take help from promise consumers that are then() method(if promise fulfilled) and catch() method (if promise is rejected).