Promise
Callback Review
- Callbacks are a traditional way to manage asynchronous code but can lead to callback hell with nested functions.
function fetchData(callback) {
setTimeout(() => {
callback("Data received");
}, 1000);
}
fetchData((data) => {
console.log(data);
});
The
fetchData
function simulates fetching data with a delay and then calls the provided callback function with the data. As more asynchronous operations are nested, this can lead to "callback hell."
Introducing Promises
- Promises provide a cleaner and more structured way to handle asynchronous operations by chaining then and catch methods.
const fetchData = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
fetchData.then((data) => {
console.log(data);
}).catch((error) => {
console.error(error);
});
The example shows a
Promise
that resolves after a delay. The.then
method handles the resolved value, and.catch
handles any errors. This approach avoids deeply nested callbacks and makes the code more readable.
Chaining Promises
- Chaining promises ensures that asynchronous tasks are executed in the correct order and errors are handled gracefully.
const fetchData = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
fetchData()
.then((data) => {
console.log(data);
return "Next task";
})
.then((nextTask) => {
console.log(nextTask);
})
.catch((error) => {
console.error(error);
});
This example shows how promises can be chained to execute tasks sequentially. The first
.then
handles the initial promise, and the second.then
handles the subsequent task. Errors in any part of the chain are caught by.catch
.
Error Handling
- Error handling is essential in asynchronous code to prevent unexpected behavior and ensure proper flow of execution.
- Promises allow for centralized error handling using the
.catch
method at the end of the chain.
const fetchData = () => new Promise((resolve, reject) => {
setTimeout(() => {
reject("Error occurred");
}, 1000);
});
fetchData()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
The
.catch
method ensures that any errors are handled properly, preventing the application from crashing unexpectedly.
Async/Await
- Async/await simplifies asynchronous programming by allowing developers to write asynchronous code in a synchronous style, making it easier to read and maintain.
const fetchData = () => new Promise((resolve) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
async function getData() {
const data = await fetchData();
console.log(data);
}
getData();
The
async
functiongetData
usesawait
to pause execution untilfetchData
resolves. This approach makes asynchronous code look and behave more like synchronous code, enhancing readability and maintainability.
Context of Promises with Async/Await
- Understanding how to use async/await within the context of promises is crucial for effective asynchronous programming in JavaScript.
const fetchData = (isError) => new Promise((resolve, reject) => {
setTimeout(() => {
if (isError) {
reject("Error occurred");
} else {
resolve("Data received");
}
}, 1000);
});
async function getData() {
try {
const data = await fetchData(false);
console.log(data);
} catch (error) {
console.error(error);
}
}
getData();
This example shows how
async
/await
is used in conjunction with promises. Thetry...catch
block handles any errors that occur during the asynchronous operation, demonstrating effective error handling within anasync
function.