Exercise
A Promise in JavaScript is an object that represents the eventual completion or failure of an asynchronous operation and its resulting value. It acts as a placeholder for a value that is not yet available but will be resolved at some point in the future. Promises allow you to write cleaner asynchronous code compared to traditional callback functions.
const myPromise = new Promise((resolve, reject) => {
// asynchronous operation here
resolve('Success!');
});
console.log(myPromise); // Promise { 'Success!' }
A Promise has three possible states: Pending - the initial state where the operation has not completed yet; Fulfilled - the operation completed successfully and the Promise has a resulting value; Rejected - the operation failed and the Promise has a reason for the failure. Once a Promise is fulfilled or rejected, it is considered settled and its state cannot change.
// Pending - not yet resolved or rejected
const pending = new Promise((resolve, reject) => {});
console.log(pending); // Promise { <pending> }
// Fulfilled - resolved with a value
const fulfilled = new Promise((resolve, reject) => {
resolve('Done');
});
// Rejected - rejected with a reason
const rejected = new Promise((resolve, reject) => {
reject('Error occurred');
});
You create a new Promise using the new Promise() constructor. It takes a single argument called the executor function, which receives two parameters: resolve and reject. These are functions provided by JavaScript that you call to settle the Promise.
const myPromise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve('Operation was successful');
} else {
reject('Operation failed');
}
});
The resolve function is used to fulfill a Promise with a value. When you call resolve(value), the Promise transitions from the pending state to the fulfilled state, and the value you pass becomes the result of the Promise. This value can then be accessed using the .then() method.
const promise = new Promise((resolve, reject) => {
const data = { name: 'Alice', age: 25 };
resolve(data); // fulfills the Promise with the data object
});
promise.then((result) => {
console.log(result); // Output: { name: 'Alice', age: 25 }
});
The reject function is used to reject a Promise with a reason (typically an error). When you call reject(reason), the Promise transitions from the pending state to the rejected state. The reason you pass can be accessed using the .catch() method or the second argument of .then().
const promise = new Promise((resolve, reject) => {
const error = new Error('Something went wrong');
reject(error); // rejects the Promise with an error
});
promise.catch((err) => {
console.log(err.message); // Output: Something went wrong
});
The .then() method is used to handle a fulfilled Promise. It takes a callback function that receives the resolved value as its argument. The .then() method itself returns a new Promise, which allows you to chain multiple .then() calls together.
const promise = new Promise((resolve, reject) => {
resolve(42);
});
promise.then((value) => {
console.log(value); // Output: 42
return value * 2;
}).then((doubled) => {
console.log(doubled); // Output: 84
});
The .catch() method is used to handle a rejected Promise. It takes a callback function that receives the rejection reason (usually an error) as its argument. It is equivalent to calling .then(null, errorHandler). Using .catch() at the end of a Promise chain will catch any error thrown in the chain.
const promise = new Promise((resolve, reject) => {
reject('Network error');
});
promise
.then((value) => {
console.log(value); // this is skipped
})
.catch((error) => {
console.log('Caught:', error); // Output: Caught: Network error
});
The .finally() method is used to run a piece of code regardless of whether the Promise was fulfilled or rejected. It does not receive any arguments and is typically used for cleanup tasks such as hiding a loading spinner or closing a database connection. The .finally() callback does not change the resolved value or rejection reason of the Promise.
const promise = new Promise((resolve, reject) => {
resolve('Data loaded');
});
promise
.then((value) => {
console.log(value); // Output: Data loaded
})
.catch((error) => {
console.log('Error:', error);
})
.finally(() => {
console.log('Cleanup complete'); // always runs
});
You can use Promise.resolve(value) to create a Promise that is immediately fulfilled with the given value. This is useful when you need to return a Promise from a function but already have the value available, or when you want to wrap a non-Promise value in a Promise for consistency.
const resolved = Promise.resolve('Hello, World!');
resolved.then((value) => {
console.log(value); // Output: Hello, World!
});
// Equivalent to:
const same = new Promise((resolve) => {
resolve('Hello, World!');
});
You can use Promise.reject(reason) to create a Promise that is immediately rejected with the given reason. This is helpful for testing error handling or for returning a rejected Promise from a function when a known error condition is met.
const rejected = Promise.reject('Something went wrong');
rejected.catch((reason) => {
console.log(reason); // Output: Something went wrong
});
// Equivalent to:
const same = new Promise((resolve, reject) => {
reject('Something went wrong');
});