// Asynchronous Code
// setInterval
// clearInterval
// outputs Hello, world! Every 2 seconds
const myInterval = setInterval(() => console.log("Hello, world!"), 2000);
clearInterval(myInterval); // Clears the Interval
// setTimeout
// clearTimeout
// Outputs Let's Play after 5 seconds
const myTimeout = setTimeout(() => console.log("Lets play"), 5000);
console.log("logging in the bottom");
// Synchronous Code
const functionOne = () => {
console.log("Function One"); // This will be printed first
functionTwo();
console.log("Function One, Part two"); // This will be printed third
};
const functionTwo = () => {
console.log("Function two"); // This will be printed second
};
// Asynchronous Code
const functionOne = () => {
console.log("Function One"); // This will be printed first
functionTwo();
console.log("Function One, Part two"); // This will be printed second
};
const functionTwo = () => {
setTimeout(() => console.log("Function two"), 2000); // This will be printed third
// Callback functions
const fetchUser = (username, callback) => {
setTimeout(() => {
callback({ username });
}, 2000);
};
fetchUser("Shubham", (user) => {
console.log(`Hello, ${user.username}`); // Hello, Shubham
});
There are two problems that we face in callbacks:-
- Callback Hell: Asynchronous operations in JavaScript can be achieved through callbacks. Whenever there are multiple dependent Asynchronous operations it will result in a lot of nested callbacks. This will cause a 'pyramid of doom' like structure.
- Inversion of control: When we give the control of callbacks being called to some other API, this may create a lot of issues. That API may be buggy, may not call our callback and create order as in the above example, may call the payment callback twice etc.
In JavaScript, a Promise is an object that represents the result of an asynchronous operation. A Promise can be in one of three states: pending, fulfilled, or rejected.
A Promise starts in the pending state, and it can either be fulfilled with a value or rejected with a reason (error). Once a Promise is fulfilled or rejected, it is considered settled, and it cannot be changed anymore.
Promises are used to handle asynchronous operations in a synchronous manner, making it easier to write and reason about async code. Instead of using callback functions, you can use the then and catch methods on a Promise to specify what should happen when the Promise is fulfilled or rejected.
// Let's say we have a shopping cart
const cart = ['shoes','pants','shirt'];
// If we had to implement a series of operations
// let's say we have a function to,
// 1. Create an order which will return a orderID
// 2. Proceed to payment with orderId and return payment info.
// 3. Show order summary with payment info
createOrder(cart,(orderID)=>{
proceedToPayment(orderID,(paymentInfo)=>{
showOrderSummary(paymentInfo,()=>{
displayOrderSummary();
})
}
})
// In the above code we see the call back hell or
// also known as Pyramid of doom
// We can write the same code using promises
createOrder(cart)
.then((orderId)=>{
return proceedToPayment(orderId)
})
.then((paymentInfo)=>{
return showOrderSummary(paymentInfo)
})
.then(()=>{
displayOrderSummary();// not returning anything because we are just displaying
})
// why do we use promises ?
// 1. To avoid Inversion of Control [Not calling the fuction over another function]
// 2. To avoid Call Back hell and have better control of our code