Modern Asynchronous JavaScript
Async/await is modern syntax that makes asynchronous code look and behave more like synchronous code, improving readability.
The 'async' keyword makes a function return a Promise, while 'await' pauses function execution until a Promise is resolved.
This approach eliminates promise chaining and makes error handling with try/catch more natural and familiar.
Example
// Traditional Promise syntax
function fetchData() {
return fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
return data;
})
.catch(error => {
console.error('Error:', error);
});
}
// Modern async/await syntax
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.error('Error:', error);
}
}
// Async function always returns a Promise
async function greet(name) {
return `Hello, ${name}!`;
}
greet('Alice').then(message => console.log(message));
// Multiple async operations in parallel
async function fetchMultiple() {
try {
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
return { users, posts, comments };
} catch (error) {
console.error('Error fetching data:', error);
}
} - async keyword - Declares an async function that returns a Promise
- await keyword - Pauses execution until Promise resolves
- try/catch - Handle errors in async functions naturally
- Sequential operations - Multiple awaits run one after another
- Parallel operations - Use Promise.all() with await for concurrent execution
- Return values - Async functions automatically wrap returns in Promise
- Top-level await - Can use await at module level in modern JS
Try Async/Await
HTML
<div class="async-demo">
<h3>Async/Await Examples</h3>
<div class="example">
<h4>1. Sequential Operations</h4>
<button id="sequentialBtn">Run Sequential</button>
<div id="sequentialOutput"></div>
</div>
<div class="example">
<h4>2. Parallel Operations</h4>
<button id="parallelBtn">Run Parallel</button>
<div id="parallelOutput"></div>
</div>
<div class="example">
<h4>3. Error Handling</h4>
<button id="successAsyncBtn">Success</button>
<button id="errorAsyncBtn">Error</button>
<div id="errorOutput"></div>
</div>
</div> CSS
.async-demo {
padding: 20px;
max-width: 600px;
}
.example {
margin: 20px 0;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
}
h4 {
margin-top: 0;
color: #333;
}
button {
padding: 10px 15px;
margin: 5px;
background: #2196F3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background: #1976D2;
}
#sequentialOutput, #parallelOutput, #errorOutput {
margin-top: 10px;
padding: 10px;
background: white;
border: 2px solid #ddd;
border-radius: 4px;
min-height: 50px;
font-family: monospace;
font-size: 13px;
}
.timing {
color: #666;
font-style: italic;
}
.success {
border-color: #4CAF50 !important;
background-color: #e8f5e9 !important;
}
.error {
border-color: #f44336 !important;
background-color: #ffebee !important;
color: #c62828;
} JavaScript
// Helper function to simulate async operations
function delay(ms, value) {
return new Promise(resolve => setTimeout(() => resolve(value), ms));
}
// Example 1: Sequential Operations
document.getElementById('sequentialBtn').addEventListener('click', async function() {
const output = document.getElementById('sequentialOutput');
output.innerHTML = 'Starting sequential operations...<br>';
const startTime = Date.now();
try {
output.innerHTML += 'Step 1: Fetching user data (1s)...<br>';
const user = await delay(1000, { name: 'Alice', id: 1 });
output.innerHTML += `✓ Got user: ${user.name}<br>`;
output.innerHTML += 'Step 2: Fetching user posts (1s)...<br>';
const posts = await delay(1000, ['Post 1', 'Post 2']);
output.innerHTML += `✓ Got ${posts.length} posts<br>`;
output.innerHTML += 'Step 3: Fetching comments (1s)...<br>';
const comments = await delay(1000, ['Comment 1', 'Comment 2', 'Comment 3']);
output.innerHTML += `✓ Got ${comments.length} comments<br>`;
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
output.innerHTML += `<br><span class="timing">Total time: ${elapsed}s (sequential)</span>`;
} catch (error) {
output.innerHTML += `Error: ${error}<br>`;
}
});
// Example 2: Parallel Operations
document.getElementById('parallelBtn').addEventListener('click', async function() {
const output = document.getElementById('parallelOutput');
output.innerHTML = 'Starting parallel operations...<br>';
const startTime = Date.now();
try {
output.innerHTML += 'Fetching all data simultaneously...<br>';
const [user, posts, comments] = await Promise.all([
delay(1000, { name: 'Bob', id: 2 }),
delay(1000, ['Post 1', 'Post 2', 'Post 3']),
delay(1000, ['Comment 1', 'Comment 2'])
]);
output.innerHTML += `✓ Got user: ${user.name}<br>`;
output.innerHTML += `✓ Got ${posts.length} posts<br>`;
output.innerHTML += `✓ Got ${comments.length} comments<br>`;
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
output.innerHTML += `<br><span class="timing">Total time: ${elapsed}s (parallel - much faster!)</span>`;
} catch (error) {
output.innerHTML += `Error: ${error}<br>`;
}
});
// Example 3: Error Handling
async function fetchWithError(shouldFail) {
await delay(500);
if (shouldFail) {
throw new Error('Network error occurred!');
}
return { data: 'Success data', status: 200 };
}
document.getElementById('successAsyncBtn').addEventListener('click', async function() {
const output = document.getElementById('errorOutput');
output.innerHTML = 'Fetching data...<br>';
try {
const result = await fetchWithError(false);
output.innerHTML += `✓ Success: ${JSON.stringify(result)}`;
output.className = 'success';
} catch (error) {
output.innerHTML += `✗ Error: ${error.message}`;
output.className = 'error';
}
});
document.getElementById('errorAsyncBtn').addEventListener('click', async function() {
const output = document.getElementById('errorOutput');
output.innerHTML = 'Fetching data...<br>';
try {
const result = await fetchWithError(true);
output.innerHTML += `✓ Success: ${JSON.stringify(result)}`;
output.className = 'success';
} catch (error) {
output.innerHTML += `✗ Error caught: ${error.message}`;
output.className = 'error';
}
}); Notes
- await only in async: The await keyword can only be used inside async functions (or at top level in modules).
- Error Handling: Use try/catch blocks to handle errors from awaited promises. Uncaught errors will reject the async function.
- Performance: Use Promise.all() with await when operations can run in parallel - it's much faster than sequential awaits.
