Node JS Promises
Promises in Node.js are a powerful way to handle asynchronous operations, providing a more manageable and readable alternative to callbacks. They represent the eventual completion (or failure) of an asynchronous operation and its resulting value. Here's a comprehensive explanation:
1. What is a Promise?
A Promise is an object that represents the eventual completion or failure of an asynchronous operation. It allows you to write asynchronous code in a more synchronous-like manner, avoiding callback hell and making code easier to manage.
A Promise can be in one of three states:
- Pending: The initial state; neither fulfilled nor rejected.
- Fulfilled: The operation completed successfully.
- Rejected: The operation failed with an error.
2. Creating a Promise
To create a Promise, use the Promise
constructor, which takes an executor function. The executor function receives two arguments: resolve
and reject
.
Example:
const myPromise = new Promise((resolve, reject) => {
// Simulate an asynchronous operation
setTimeout(() => {
const success = true; // Simulate success or failure
if (success) {
resolve('Operation successful');
} else {
reject('Operation failed');
}
}, 1000);
});
In this example:
resolve
is called when the operation completes successfully.reject
is called when the operation fails.
3. Using Promises
Once a Promise is created, you can handle its result using .then()
and .catch()
methods:
Example:
myPromise
.then(result => {
console.log(result); // Output: 'Operation successful'
})
.catch(error => {
console.error(error); // Output: 'Operation failed'
});
.then(onFulfilled, onRejected)
: Handles the fulfillment or rejection of the Promise.onFulfilled
is called when the Promise is resolved.onRejected
is called when the Promise is rejected.
.catch(onRejected)
: Handles only the rejection of the Promise. It's a shorthand for.then(null, onRejected)
.
4. Chaining Promises
Promises can be chained to perform sequential asynchronous operations:
Example:
const doSomething = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('Step 1 complete'), 1000);
});
};
const doSomethingElse = (message) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${message} -> Step 2 complete`), 1000);
});
};
doSomething()
.then(result => {
console.log(result); // Output: 'Step 1 complete'
return doSomethingElse(result);
})
.then(finalResult => {
console.log(finalResult); // Output: 'Step 1 complete -> Step 2 complete'
})
.catch(error => {
console.error('Error:', error);
});
In this example:
doSomething
anddoSomethingElse
return Promises..then()
is used to chain the operations and handle their results sequentially..catch()
handles any errors that occur in the chain.
5. Promise.all()
Promise.all()
is used to execute multiple Promises in parallel and wait for all of them to complete.
Example:
const promise1 = new Promise((resolve) => setTimeout(() => resolve('Result 1'), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve('Result 2'), 2000));
Promise.all([promise1, promise2])
.then(results => {
console.log(results); // Output: ['Result 1', 'Result 2']
})
.catch(error => {
console.error('Error:', error);
});
In this example:
Promise.all()
waits for all Promises to resolve and returns an array of results.- If any of the Promises reject, the returned Promise is rejected immediately with the reason of the first rejection.
6. Promise.race()
Promise.race()
returns a Promise that resolves or rejects as soon as one of the Promises in the iterable resolves or rejects.
Example:
const promise1 = new Promise((resolve) => setTimeout(() => resolve('Result 1'), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve('Result 2'), 2000));
Promise.race([promise1, promise2])
.then(result => {
console.log(result); // Output: 'Result 1'
})
.catch(error => {
console.error('Error:', error);
});
In this example:
Promise.race()
resolves with the result of the first Promise that completes, regardless of whether it resolves or rejects.
7. Promise.finally()
Promise.finally()
is used to execute a cleanup action regardless of the Promise's outcome (whether it resolves or rejects).
Example:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => resolve('Done'), 1000);
});
myPromise
.then(result => {
console.log(result); // Output: 'Done'
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log('Cleanup or final actions'); // Output: 'Cleanup or final actions'
});
Summary
- Promises: Objects representing the eventual result of an asynchronous operation.
- States: Pending, fulfilled, and rejected.
- Methods:
.then()
,.catch()
,.finally()
,Promise.all()
,Promise.race()
. - Advantages: More readable and manageable than nested callbacks, and easier to handle errors and multiple asynchronous operations.