A Promise is created with the Promise constructor, which takes an executor function. The executor gets two functions:
- resolve(value) → marks promise as fulfilled
- reject(reason) → marks promise as rejected
Example:
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('Data loaded successfully');
} else {
reject('Error loading data');
}
}, 1000);
});A promise is used with:
- .then() → when fulfilled
- .catch() → when rejected
- .finally() → runs regardless of result
fetchData
.then((result) => console.log(result))
.catch((error) => console.error(error))
.finally(() => console.log('Request complete'));Each .then() returns a new Promise, allowing you to chain async operations in sequence.
Example:
getUser(1)
.then((user) => getPosts(user.id)) // returns promise
.then((posts) => getComments(posts[0].id))
.then((comments) => console.log(comments))
.catch((err) => console.error(err));Flow:
getUserresolves → passes user to next.then()getPostsresolves → passes posts to next.then()getCommentsresolves → final.then()logs data
💡 This avoids callback hell by flattening the structure.
If any promise in the chain rejects, control jumps to the nearest .catch().
getUser(1)
.then((user) => getPosts(user.id))
.then((posts) => {
throw new Error('Failed to load posts');
})
.then((posts) => getComments(posts[0].id))
.catch((err) => console.error('Error:', err.message));Even the thrown error inside .then() goes to .catch().
You can handle errors at different points, but best practice is usually one final .catch() unless specific cases need separate handling.
Runs regardless of success/failure — useful for cleanup.
fetchData
.then((data) => console.log(data))
.catch((err) => console.error(err))
.finally(() => console.log('Finished operation'));To create a Promise, you use the new Promise constructor with an executor that calls resolve on success or reject on failure. Chaining works because each .then() returns a new Promise, passing results down the chain, which keeps async code flat and readable. Errors are handled with .catch(), which catches both rejections and exceptions thrown inside .then(). .finally() runs after completion regardless of the outcome.