Promises in JavaScript might sound like a mystical concept, but they're just a way to handle things that might take some time, like fetching data from the web. It's like ordering a pizza: you make the order (start an action) and you're given a time frame. You don’t get your pizza immediately, but you get a promise that it'll come in, say, 20 minutes.
What is a Promise?
In JavaScript, a Promise is an object representing the eventual completion or failure of an asynchronous operation. Asynchronous just means that you can start something (like fetching data) and continue doing other things without waiting for that initial task to complete.
Think of it as if you've set a pot of water to boil. You don't have to stand there and watch it. Instead, you set it, and when it's boiling (done), you can make your tea.
A Promise has three states:
- Pending: The initial state. It's neither fulfilled nor rejected.
- Fulfilled: The action relating to the promise succeeded.
- Rejected: The action relating to the promise failed.
How to Create a Promise?
A basic promise can be created using the Promise
constructor:
let myFirstPromise = new Promise((resolve, reject) => {
// some asynchronous operation
if (everythingIsFine) {
resolve('Success!');
} else {
reject('Error!');
}
});
Here, resolve
and reject
are functions that get called when the operation is successful or fails, respectively.
Handling Promises
After creating a promise, you can specify what should happen when it's successful or when it fails.
Example 1: Basic Promise Usage
myFirstPromise
.then(result => {
console.log(result); // This will print "Success!" if everything was fine
})
.catch(error => {
console.error(error); // This will print "Error!" if there was an issue
});
Example 2: Simulating a Delay with setTimeout
Here's a promise that simulates a delay using setTimeout
:
let delayedHello = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello after 2 seconds');
}, 2000);
});
delayedHello.then(alert); // This will show an alert with the message after 2 seconds.
Example 3: Using fetch
to Get Data from the Web
The fetch
function in JavaScript returns a promise. This function fetches data from a URL:
fetch('https://api.example.com/data')
.then(response => response.json()) // Convert the response to JSON format
.then(data => {
console.log(data);
})
.catch(error => {
console.error('There was an error fetching data:', error);
});
Example 4: Chaining Promises
You can chain .then()
to transform values or run more async actions one after another:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
return data.length; // Return the length of data
})
.then(length => {
console.log('Data count:', length);
});
Example 5: Error Propagation
If a promise in a chain rejects, subsequent .then
handlers are skipped until a .catch
is found:
new Promise((resolve, reject) => {
reject('Error occurred!');
})
.then(() => {
console.log('This will not be called');
})
.catch(error => {
console.error(error); // This will print "Error occurred!"
});
Example 6: Handling Multiple Promises
Sometimes, you might want to run multiple promises simultaneously. Promise.all()
helps with that:
let promise1 = fetch('https://api.example.com/data1');
let promise2 = fetch('https://api.example.com/data2');
Promise.all([promise1, promise2])
.then(responses => {
return Promise.all(responses.map(r => r.json()));
})
.then(datas => {
console.log('Data1:', datas[0]);
console.log('Data2:', datas[1]);
});
Example 7: The First Promise to Complete
If you want to act on whichever promise completes first, you can use Promise.race()
:
let promiseFast = new Promise((resolve) => setTimeout(resolve, 100, 'Fast'));
let promiseSlow = new Promise((resolve) => setTimeout(resolve, 500, 'Slow'));
Promise.race([promiseFast, promiseSlow]).then(result => {
console.log(result); // Will print "Fast"
});
Example 8: Creating an Immediately Resolved Promise
Sometimes, for testing or other reasons, you might want a promise that resolves immediately:
Promise.resolve('Instant').then(console.log); // Will print "Instant"
Example 9: Creating an Immediately Rejected Promise
Similarly, you can create a promise that rejects immediately:
Promise.reject('Immediate Error').catch(console.error); // Will print "Immediate Error"
Example 10: Handling Finally
Regardless of success or failure, you can use .finally
to run some code:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('There was an error fetching data:', error);
})
.finally(() => {
console.log('Finished fetching data.');
});
In Conclusion
Promises in JavaScript make handling asynchronous tasks simpler and more readable. They allow you to perform tasks without waiting for previous tasks to complete, making your programs more efficient. As you can see from the examples above, promises offer a structured approach to handle both the success and failure cases, giving developers better control over the flow of their programs.