Skip to main content

Promises in javascript

Definition

  1. Promises in JavaScript are a programming pattern used to handle asynchronous operations. They allow you to write code that can execute asynchronously and provide a way to handle success or failure of that asynchronous operation.

  2. A promise is an object that represents the eventual completion (or failure) of an asynchronous operation, and provides a way to register callbacks to be executed when the operation completes.

  3. A promise has three states:

  • Pending: The initial state, before the promise has resolved or rejected.
  • Fulfilled: The state of a promise when it has successfully completed. This is also known as "resolved."
  • Rejected: The state of a promise when it has failed to complete. This is also known as "rejected."

How to create promise

Promises are created using the Promise constructor, which takes a function called an executor as its argument. The executor function takes two arguments: a resolve function and a reject function. When the asynchronous operation is complete, you call one of these functions to resolve or reject the promise.

const promise = new Promise((resolve, reject) => {
// Perform some asynchronous operation
// When it's done, call resolve() with the result
// or reject() with an error if something went wrong.
});

The new Promise constructor is invoked, and the executor function is executed synchronously

Once a promise is created, you can attach callbacks to it using the then() and catch() methods. The then() method takes a callback that will be executed if the promise is fulfilled, and the catch() method takes a callback that will be executed if the promise is rejected.

promise
.then((result) => {
// Do something with the result
})
.catch((error) => {
// Handle the error
});

You can also chain multiple then() methods together to create a sequence of asynchronous operations. Each then() method takes a callback that returns a new promise. If the callback returns a value, the new promise is fulfilled with that value. If the callback throws an error or returns a rejected promise, the new promise is rejected with that error.

Before Promises

Before the introduction of Promises in JavaScript, the primary mechanism for handling asynchronous operations was through traditional callback functions. Callbacks were used to specify what should happen when an asynchronous operation completed or encountered an error.

problems with this approach

  1. Callback hell- Asynchronous code that involved multiple nested callbacks could quickly become difficult to read and maintain. This nesting structure, often referred to as "callback hell" or "pyramid of doom," made code hard to understand, debug, and reason about

  2. Error Handling- Error handling in callback-based code could be cumbersome. Errors often had to be passed as parameters to the callbacks, and it was the responsibility of each callback to handle errors appropriately. This approach made it challenging to centralize error handling and propagate errors across the codebase.

  3. Lack of structure- Without a standardized mechanism for handling asynchronous operations, developers had to rely on individual coding patterns and conventions. This lack of structure led to inconsistency and made it harder to share and reuse asynchronous code.

  4. inversion of control- -it not actually a problem. it is good design pattern with callback may create a problem -giving control to different part of code -less reuseable

Promise API

There are 6 static methods in the Promise class. We’ll quickly cover their use cases here.

  • Promise.all
  • Promise.any
  • Promise.race
  • Promise.allSettled
  • Promise.resolve
  • Promise.reject

MCQ

BASICS:

console.log("start");
const promise1 = new Promise((resolve, reject) => {
console.log(1);
});
console.log("end");

Why output is start,1,end : The new Promise constructor is invoked, and the executor function is executed synchronously

console.log("start");
const promise1 = new Promise((resolve, reject) => {
console.log(1);
resolve(2);
});
promise1.then((res) => {
console.log(res);
});
console.log("end");
console.log("start");
const promise1 = new Promise((resolve, reject) => {
console.log(1);
resolve(2);
console.log(3);
});
promise1.then((res) => {
console.log(res);
});
console.log("end");
console.log("start");
const promise1 = new Promise((resolve, reject) => {
console.log(1);
});
promise1.then((res) => {
console.log(2);
});
console.log("end");
console.log("start");
const fn = () =>
new Promise((resolve, reject) => {
console.log(1);
resolve("success");
});
console.log("middle");
fn().then((res) => {
console.log(res);
});

console.log("end");
console.log("start");
setTimeout(() => {
console.log("setTimeout");
});
Promise.resolve().then(() => {
console.log("resolve");
});
console.log("end");
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);
console.log("start");

const promise1 = Promise.resolve().then(() => {
console.log("promise1");
const timer2 = setTimeout(() => {
console.log("timer2");
}, 0);
});

const timer1 = setTimeout(() => {
console.log("timer1");

const promise2 = Promise.resolve().then(() => {
console.log("promise2");
});
}, 0);

console.log("end");

What will log ?

let p = new Promise((resolve, rejected) => {
setTimeout(() => {
rejected("200");
}, 2000);
});

p.then(
(res) => {
console.log("res", res);
},
(err) => {
console.log("err", err);
}
);

what will log ?

let p = new Promise((resolve, rejected) => {
setTimeout(() => {
resolve("200");
}, 2000);
});

p.then(
(res) => {
console.log("res", res);
},
(err) => {
console.log("err", err);
}
);

What do you think? Will the .catch trigger? Explain your answer.

new Promise(function (resolve, reject) {
setTimeout(() => {
throw new Error("Whoops!");
}, 1000);
}).catch(alert);
Answer

The task doesn't explain why .catch is not invoked. .catch will be invoked when we have a rejected promise More important fact is that .then or .catch are invoked only when promise is settled. For resolved promise .then is invoked and for rejected .catch is invoked. Now the question is when does promise is consider rejected?

  • case 1 . The executer function is having synchronous code. any error("exception") occurred here OR any error thrown explicitly here OR call to reject function ( like ex reject('my errr message '))

the promise is rejected;

  • case 2 . The executer function is having some async code.

if INSIDE the async code (ex setTimeout),you throw / or get any error it won't cause promise to be rejected. if you want to reject the promise from inside async code, you need to call reject method . ( like ex reject('my errr message '))

this is exactly what is happening in given task.

Question 1

// This doesn't make sense w/ promises:
console.log(Promise.resolve(42));

// We must use the `.then` interface:
Promise.resolve(42).then((value) => console.log(value));
Answer

The answer 42

Question 2

function job(state) {
return new Promise(function (resolve, reject) {
if (state) {
resolve("success");
} else {
reject("error");
}
});
}

let promise = job(true);

promise
.then(function (data) {
console.log(data);
return job(false);
})
.catch(function (error) {
console.log(error);
return "Error caught";
})
.then(function (data) {
console.log(data);
return job(true);
})
.catch(function (error) {
console.log(error);
});

// 1. error, success, Error caught
// 2. success, success
// 3. success, error, success, error
// 4. success, error, Error caught
// 5. error, Error caught, success
// 6. error, Error caught, success, error
// 7. success, error, error
// 8. success, success, success
Answer
  1. success, error, Error caught

Question 3

function job() {
return new Promise(function (resolve, reject) {
reject();
});
}

let promise = job();

promise

.then(function () {
console.log("Success 1");
})

.then(function () {
console.log("Success 2");
})

.then(function () {
console.log("Success 3");
})

.catch(function () {
console.log("Error 1");
})

.then(function () {
console.log("Success 4");
});

// 1. Error 1
// 2. Success 1, Error 1
// 3. Success 1, Success 2, Success 3, Success 4
// 4. Success 1, Success 2, Success 3, Error 1, Success 4
// 5. Error 1, Success 1, Success 2, Success 3, Succes 4
// 6. Error 1, Success 4
Details

Answer 6. Error 1, Success 4

Question 4

    var p = new Promise((resolve, reject) => {
reject(Error('The Fails!'))
})
p.catch(error => console.log(error.message))
p.catch(error => console.log(error.message))

// output
A. print message once
B. print message twice
C. UnhandledPromiseRejectionWarning
D. process exits
Answer

B. print message twice

Question 5


var p = new Promise((resolve, reject) => {
return Promise.reject(Error('The Fails!'))
})
p.catch(error => console.log(error.message))
p.catch(error => console.log(error.message))
// output
A. print message once
B. print message twice
C. UnhandledPromiseRejectionWarning
D. process exits
Details

Answer C. UnhandledPromiseRejectionWarning

Question 6

    var p = new Promise((resolve, reject) => {
reject(Error('The Fails!'))
})
.catch(error => console.log(error))
.then(error => console.log(error))
// output
A. print error and `undefined`
B. print error twice
C. UnhandledPromiseRejectionWarning
D. undefined
Details

Answer A. print error and undefined

Question 7

    Promise.resolve('Success!')
.then(data => {
data.toUpperCase()
})
.then(data => {
console.log(data)
})
// output
A. print "SUCCESS!"
B. print "Success!"
C. print "SUCCESS!" and "SUCCESS!"
D. prints `undefined`
Details

Answer D. prints undefined

Question 8

    var p = new Promise((resolve, reject) => {
reject(Error('The Fails!'))
})
.catch(error => console.log(error.message))
.catch(error => console.log(error.message))
// output
A. print error message once
B. print error message twice
C. UnhandledPromiseRejectionWarning
D. process exits
Details

Answer A. print error message once

Question 9

    new Promise((resolve, reject) => {
resolve('Success!')
})
.then(() => {
throw Error('Oh noes!')
})
.catch(error => {
return "actually, that worked"
})
.catch(error => console.log(error.message))
// output
A. print message once
B. print error message twice
C. UnhandledPromiseRejectionWarning
D. nothing prints
Details

Answer D. nothing prints

  1. Implement custom javascript promises
  2. Implement custom Promise.all
  3. Implement custom Promise.any
  4. Implement custom Promise.race
  5. Implement custom Promise.allSettled

Question to answere after understaing promise

  • What is a Promise in JavaScript?
  • Explain the three states of a Promise.
  • How do you create a Promise in JavaScript?
  • How do you handle the fulfillment and rejection of a Promise?
  • What are the differences between using Promises and traditional callback functions for handling asynchronous operations?
  • How do you chain Promises together?
  • How do you handle errors in a Promise chain?
  • What is the purpose of the .catch() method in a Promise chain?
  • Explain the difference between Promise.all() and Promise.race().
  • How do you convert callback-based functions into Promise-based functions?
  • What are some common anti-patterns or pitfalls to avoid when working with Promises?
  • How does async/await syntax relate to Promises? How do you use async/await with Promises?
  • How would you handle multiple Promises in parallel?
  • Explain how to implement a timeout for a Promise.
  • What are the advantages of using Promises over callbacks?
  • How do you handle asynchronous code that relies on multiple Promises and requires them to be executed in a specific order?
  • How do you handle situations where you need to limit the concurrency of multiple asynchronous operations using Promises?
  • How do you handle cancellation of a Promise-based asynchronous operation?
  • How do you handle retries for a Promise-based asynchronous operation that may fail?
  • How do you handle long-running Promises to prevent them from blocking the main JavaScript thread?
  • How do you handle the situation when you have a mix of Promises and non-Promise asynchronous operations and need to ensure they are all completed before proceeding?
  • How do you handle timeouts for Promises, ensuring that they don't exceed a certain duration?
  • How do you handle multiple Promises in parallel and wait for all of them to resolve?
  • How do you handle multiple Promises in parallel and wait for the first one to resolve?
  • How do you handle multiple Promises in parallel and wait for at least a certain number of them to resolve?
  • How do you handle multiple Promises in parallel and wait for the first one to reject?
  • How do you handle multiple Promises in parallel and wait for at least one of them to reject?
  • How do you handle the situation when you need to pass data between Promises in a chain?
  • How do you handle the situation when you need to perform cleanup actions after a Promise chain completes, regardless of whether it resolved or rejected?
  • How do you handle the situation when you want to create a custom Promise that wraps a callback-based asynchronous operation?
  • How do you handle the situation when you want to create a Promise that resolves or rejects after a specific delay?
  • How do you handle the situation when you want to create a Promise that resolves immediately with a specific value?
  • How do you implement a custom Promise-like object from scratch, without using the built-in Promise constructor?
  • How do you handle circular dependencies or interdependent Promises in a complex asynchronous scenario?
  • How do you handle memory leaks when working with Promises that are not properly cleaned up?
  • How do you handle race conditions or synchronization issues when multiple Promises are updating shared data?
  • How do you handle complex error handling scenarios, such as retrying with exponential backoff and error propagation in a Promise chain?
  • How do you handle Promises that rely on external resources, such as network requests, and need to implement timeouts, retries, and cancellation?
  • How do you handle Promises in a multi-threaded environment, such as a web worker or Node.js cluster?
  • How do you optimize performance and reduce unnecessary Promise overhead in high-throughput applications?
  • How do you handle Promise composition and nesting when dealing with complex data transformations and dependencies?
  • How do you handle the situation when you need to extend or subclass the built-in Promise object to add custom behavior?
  • Implement a function retryWithDelay that takes a function asyncOperation and a maximum number of retries maxRetries. The asyncOperation is an asynchronous function that returns a Promise. The retryWithDelay function should attempt to execute the asyncOperation up to maxRetries times, with an increasing delay between each retry. If the operation fails after all retries, the function should reject with the last error encountered. Implement the retryWithDelay function using Promises and demonstrate its usage with an example.