| Destructuring | Optional chaining | |
π Deep Dive: Async/Await in JavaScript |
In JavaScript, async/await is a modern, clean, and highly readable syntax for writing asynchronous code, introduced in ECMAScript 2017. It is syntactic sugar built on top of Promises, simplifying their use by making asynchronous operations appear more like synchronous code.
async and await are syntactic sugar built on top of Promises, introduced in ES2017. They make asynchronous code look and behave more like synchronous code, improving readability and maintainability.
// Define an async function
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
fetchData();
async functions always return a Promise.await pauses the execution until the Promise resolves or rejects.You must declare a function with the async keyword to use the await keyword inside it.
An async function always returns a Promise. Any value you explicitly return from an async function is automatically wrapped in a resolved Promise.
If an exception is thrown inside an async function, the returned Promise is automatically rejected with that error.
The await keyword is used inside an async function to pause its execution until the Promise it is waiting for is settled (resolved or rejected).
It then returns the resolved value of the Promise. In case of a rejection, await throws an exception, which can be caught with a try...catch block.
Crucially, await does not block the entire main thread of JavaScript. It only pauses the execution of the async function itself, allowing the rest of the program to continue.
When the JavaScript engine encounters async/await, it transforms the code into a state machine at compile-time.
Encountering await: When an await is hit, the engine pauses the execution of the async function and puts the rest of the function in a queue (the Microtask Queue) to be run later.
Unblocking the main thread: The engine is now free to execute other synchronous code.
Resuming execution: When the awaited Promise is settled, the event loop picks the paused function from the Microtask Queue and pushes it back onto the Call Stack to continue its execution right where it left off.
To avoid awaiting sequential, independent promises, run them concurrently using Promise.all() and then await the result.
//javascript
async function fetchMultipleUrls(urls) {
try {
const promises = urls.map(url => fetch(url));
const responses = await Promise.all(promises);
const data = await Promise.all(responses.map(res => res.json()));
return data;
} catch (error) {
console.error("Error fetching data:", error);
}
}
Always wrap your await calls in a try...catch block to handle potential promise rejections gracefully.
//javascript
async function getUser(id) {
try {
const response = await fetch(`https://api.example.com/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Failed to fetch user:", error);
// You can re-throw or return a default value
return null;
}
}
If you are working in an ES module environment (e.g., modern browsers or Node.js with "type": "module"), you can use await at the top level without an async function.
//javascript
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
async functionsPromise.all)try/catch)Promise.all instead)try/catch for error handlingPromise.all for parallel execution(async () => {
const result = await fetchData();
})();
map() and Promise.all() for batch processing:
const urls = ['url1', 'url2']; const results = await Promise.all(urls.map(url => fetch(url)));
| Destructuring | Optional chaining | |