Mind~G
Javascript

Promise

A Promise in JavaScript is a special type of object that represents something that will happen in the future. It is used to handle asynchronous operations. Asynchronous means tasks that take time like fetching data from a server or reading a file.

Promise is a good way to handle these operations because it makes your code cleaner and easier to understand.

Think of it like ordering food at a restaurant. When you order, you get a receipt (the promise). The food is not ready yet, but you know it will come soon. Either you will get your food (success) or the kitchen might tell you they ran out (failure).

Why do we need Promises

Before Promises, we used callbacks. But callbacks created a big problem called callback hell.

What is Callback Hell

Callback hell happens when you have many callbacks inside callbacks. The code starts looking like a pyramid or staircase going to the right.

getData(function(a) {
  getMoreData(a, function(b) {
    getMoreData(b, function(c) {
      getMoreData(c, function(d) {
        getMoreData(d, function(e) {
          console.log("Finally done")
        })
      })
    })
  })
})

This code is very hard to read and understand. It looks messy and ugly. This is callback hell.

Problems with Callback Hell

  1. Code becomes hard to read
  2. Difficult to find and fix bugs
  3. Hard to handle errors properly
  4. Cannot easily add new features
  5. Makes your code look unprofessional in interviews

How Promise solves this problem

A Promise makes the code look flat and clean instead of a pyramid.

Promise has three states

  1. Pending: The task is still running
  2. Fulfilled: The task finished successfully (also called Resolved)
  3. Rejected: The task failed with an error

A Promise starts in Pending state. Then it moves to either Fulfilled or Rejected. Once a Promise is fulfilled or rejected, it cannot change again.

Creating a Promise

We create a Promise using the Promise constructor. The constructor takes one callback function as a parameter. This callback function gets two arguments: resolve and reject.

let myPromise = new Promise(function(resolve, reject) {
  let success = true
  
  if (success) {
    resolve("Task completed")
  } else {
    reject("Task failed")
  }
})

Important: At one time, you can only call either resolve or reject. You cannot call both. Once you call one of them, the Promise is done.

Using a Promise

Promises have three methods to handle the result:

  1. then() method is used to handle resolved promise. It takes one callback function as a parameter. This callback receives the data that we passed in resolve.

  2. catch() method is used to handle rejected promise. It takes one callback function as a parameter. This callback receives the error.

  3. finally() method is used to run code after both resolved and rejected promise. It always executes no matter what happens.

myPromise
  .then(function(result) {
    console.log(result)
  })
  .catch(function(error) {
    console.log(error)
  })
  .finally(function() {
    console.log("Promise is completed")
  })

Important: Both then() and catch() methods return a new promise. This is why we can chain them together.

Real world example

Without Promise (Callback Hell)

function orderFood(callback) {
  setTimeout(function() {
    console.log("Food ordered")
    callback()
  }, 1000)
}
 
function cookFood(callback) {
  setTimeout(function() {
    console.log("Food cooked")
    callback()
  }, 1000)
}
 
function serveFood(callback) {
  setTimeout(function() {
    console.log("Food served")
    callback()
  }, 1000)
}
 
orderFood(function() {
  cookFood(function() {
    serveFood(function() {
      console.log("Enjoy your meal")
    })
  })
})

With Promise (Clean Code)

function orderFood() {
  return new Promise(function(resolve) {
    setTimeout(function() {
      console.log("Food ordered")
      resolve()
    }, 1000)
  })
}
 
function cookFood() {
  return new Promise(function(resolve) {
    setTimeout(function() {
      console.log("Food cooked")
      resolve()
    }, 1000)
  })
}
 
function serveFood() {
  return new Promise(function(resolve) {
    setTimeout(function() {
      console.log("Food served")
      resolve()
    }, 1000)
  })
}
 
orderFood()
  .then(function() {
    return cookFood()
  })
  .then(function() {
    return serveFood()
  })
  .then(function() {
    console.log("Enjoy your meal")
  })

See how much cleaner this looks? No more pyramid of doom.

Promise chaining

You can chain multiple promises together using .then()

fetchUser()
  .then(function(user) {
    return fetchPosts(user.id)
  })
  .then(function(posts) {
    return fetchComments(posts[0].id)
  })
  .then(function(comments) {
    console.log(comments)
  })
  .catch(function(error) {
    console.log("Something went wrong:", error)
  })

Each .then() waits for the previous one to finish. If any step fails, the .catch() will handle the error.

Important: How Promises run in JavaScript

This is very important for interviews. When you have both setTimeout and Promise in your code, the Promise runs first. Let me explain why.

JavaScript has two queues:

  1. Micro Queue: All .then() and .catch() methods are stored here
  2. Callback Queue: All setTimeout methods are stored here

The Micro Queue has higher priority. JavaScript always checks Micro Queue first and runs everything there before looking at Callback Queue.

Example

console.log("Start")
 
setTimeout(function() {
  console.log("setTimeout")
}, 0)
 
Promise.resolve().then(function() {
  console.log("Promise")
})
 
console.log("End")

Output

Start
End
Promise
setTimeout

Even though setTimeout has 0 delay, Promise runs first because Promises go to Micro Queue which runs before Callback Queue.

Remember this for interviews: Promises are faster than setTimeout because Micro Queue is checked first.

Interview tips

When asked about callback hell in interviews, mention:

  1. Callback hell is nested callbacks that make code hard to read
  2. It happens when one callback depends on another callback
  3. The code looks like a pyramid going to the right
  4. Promises solve this problem by making code flat and readable
  5. Promises also make error handling easier with .catch()
  6. Modern JavaScript uses async/await which makes Promises even cleaner

When asked about Promises in interviews, mention:

  1. Promise is a special type of object for handling asynchronous operations
  2. Promise has three states: Pending, Fulfilled, and Rejected
  3. We create Promise using new Promise constructor
  4. Promise constructor takes one callback function with resolve and reject
  5. We can only call resolve or reject once, not both
  6. Promise has three methods: then(), catch(), and finally()
  7. Both then() and catch() return new promises so we can chain them
  8. Promises go to Micro Queue which runs before Callback Queue

Common interview questions

Question 1: What is callback hell and how do you avoid it?

Good Answer: Callback hell happens when we nest multiple callbacks inside each other. This makes the code hard to read and maintain. We can avoid it by using Promises or async/await. Promises let us chain operations using .then() which keeps the code flat and readable. We can also handle all errors in one place using .catch().

Question 2: What are the three states of a Promise?

Good Answer: A Promise has three states. First is Pending when the task is still running. Second is Fulfilled or Resolved when the task completes successfully. Third is Rejected when the task fails with an error. A Promise starts in Pending state and then moves to either Fulfilled or Rejected. Once it changes state, it cannot change again.

Question 3: Why do Promises run before setTimeout?

Good Answer: Promises run before setTimeout because of how JavaScript handles the event loop. JavaScript has two queues. Promises and their .then() and .catch() methods go to the Micro Queue. setTimeout goes to the Callback Queue. JavaScript always checks and runs everything in the Micro Queue first before checking the Callback Queue. This is why even if setTimeout has 0 delay, Promises will still run first.

Question 4: How do you handle the result of a Promise?

Good Answer: You can use the .then() method to handle the successful resolution of a Promise and the .catch() method to handle any errors that occur. The .then() method gets the data when the Promise is resolved, and .catch() gets the error when the Promise is rejected.

Question 5: What is the purpose of the async keyword in JavaScript?

Good Answer: The async keyword is used to define an asynchronous function that returns a Promise. When you put async before a function, that function automatically returns a Promise. This allows you to write asynchronous code in a cleaner way.

Question 6: What is the purpose of the await keyword in JavaScript?

Good Answer: The await keyword is used to pause the execution of an async function until a Promise is resolved or rejected. It makes your code wait for the Promise to finish before moving to the next line. You can only use await inside an async function.

Question 7: How do you handle errors in an async/await function?

Good Answer: You can use a try/catch block to handle errors that occur in an async/await function. You put your await code inside the try block, and if any error happens, it will be caught in the catch block. This makes error handling very simple and clean.

Question 8: What is the purpose of the Promise.prototype.then() method?

Good Answer: The Promise.prototype.then() method is used to handle the successful resolution of a Promise. When a Promise completes successfully, the .then() method runs and receives the data that was passed to the resolve function. You can also chain multiple .then() methods together.

Question 9: What is callback vs Promise?

Good Answer: A callback is a function that is passed as an argument to another function, and it is called when the operation is complete. A Promise, on the other hand, is a value that represents the eventual completion or failure of an asynchronous operation. The main difference is that a callback is used for executing code after an asynchronous operation completes, while a Promise is used for returning a value or error after the operation completes. Promises also help avoid callback hell by making code cleaner.

Question 10: What is Promise vs async?

Good Answer: Promise is an object that represents the eventual completion or failure of an asynchronous operation, while async is a keyword that is used to define a function that returns a Promise. The async keyword allows you to write asynchronous code that looks synchronous, making it easier to read and understand.

Question 11: What is await in JavaScript?

Good Answer: await is a keyword in JavaScript that is used inside an async function to pause the execution of the function until a Promise is resolved. It makes your code wait for the Promise to complete before moving forward. It can only be used inside an async function, not in regular functions.

Question 12: Does await return a Promise?

Good Answer: Yes, await returns a Promise. When you use await to pause the execution of an async function until a Promise is resolved, the value of the resolved Promise is returned by the await keyword. If the Promise is rejected, an error is thrown which you can catch using try/catch.

On this page