JavaScript Promises Tutorial - Section 1: Introduction
A Promise is an object representing the eventual completion (or failure) of an asynchronous operation.
Think of it like a receipt for an async operation:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
console.log(promise); // Promise { <pending> }
A Promise is always in one of three states:
Initial state, neither fulfilled nor rejected.
const promise = new Promise((resolve, reject) => {
// Still waiting...
});
console.log(promise); // Promise { <pending> }
Operation completed successfully.
const promise = new Promise((resolve, reject) => {
resolve('Success!');
});
// Promise { 'Success!' }
Operation failed.
const promise = new Promise((resolve, reject) => {
reject(new Error('Failed!'));
});
// Promise { <rejected> Error: Failed! }
Important: Once a Promise is fulfilled or rejected, it cannot change state (it's immutable).
const myPromise = new Promise((resolve, reject) => {
// Do async work here
if (/* success */) {
resolve(value); // Fulfill the promise
} else {
reject(error); // Reject the promise
}
});
function fetchUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id > 0) {
resolve({ id: id, name: 'John Doe' });
} else {
reject(new Error('Invalid user ID'));
}
}, 1000);
});
}
const userPromise = fetchUser(1);
console.log(userPromise); // Promise { <pending> }
Use .then() to handle success and .catch() to handle errors:
fetchUser(1)
.then(user => {
console.log('User:', user);
})
.catch(error => {
console.error('Error:', error.message);
});
getUser(1, (error, user) => {
if (error) return console.error(error);
getOrders(user.id, (error, orders) => {
if (error) return console.error(error);
getDetails(orders[0].id, (error, details) => {
if (error) return console.error(error);
console.log(details);
});
});
});
getUser(1)
.then(user => getOrders(user.id))
.then(orders => getDetails(orders[0].id))
.then(details => console.log(details))
.catch(error => console.error(error));
Benefits:
| Feature | Callbacks | Promises |
|---|---|---|
| Readability | Nested, hard to read | Flat, chainable |
| Error Handling | Repeated in each callback | Single .catch() |
| Composition | Difficult | Easy with .then() |
| Return Values | Cannot return | Returns new Promise |
| Standard API | No standard | Standardized |
They start executing immediately when created:
const promise = new Promise((resolve) => {
console.log('Executing now!'); // Runs immediately
resolve();
});
Once settled (fulfilled/rejected), they cannot change:
const promise = new Promise((resolve, reject) => {
resolve('First');
resolve('Second'); // Ignored!
reject('Error'); // Ignored!
});
.then() always returns a new Promise:
const promise1 = Promise.resolve(1);
const promise2 = promise1.then(x => x + 1);
const promise3 = promise2.then(x => x + 1);
promise3.then(result => console.log(result)); // 3
function checkInventory(item) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const inStock = Math.random() > 0.3;
if (inStock) {
resolve({ item, quantity: 10 });
} else {
reject(new Error(`${item} is out of stock`));
}
}, 1000);
});
}
checkInventory('laptop')
.then(inventory => {
console.log('In stock:', inventory);
return inventory;
})
.catch(error => {
console.error('Error:', error.message);
});
.then() for success, .catch() for errorsIn the next section, we'll dive deeper into: