JavaScript Asynchronous Operations
Master real-world async operations like API calls, file handling, and timers
🌐 Asynchronous Operations
Asynchronous operations are tasks that don't block the main thread while waiting for completion. Common examples include API calls, file operations, timers, and user interactions.
// Real-world async operation - API call
async function fetchWeather(city) {
try {
const response = await fetch(`/api/weather?city=${city}`);
const data = await response.json();
return data;
} catch (error) {
console.error("Weather fetch failed:", error);
}
}
Result:
Non-blocking API call that returns weather data
Common Async Operations
API Calls
Fetch data from external services
const response = await fetch('/api/users');
const users = await response.json();
Timers
Delay execution or repeat tasks
setTimeout(() => console.log("Done"), 2000);
setInterval(() => console.log("Tick"), 1000);
File Operations
Read and write files asynchronously
const file = await fetch('/data.json');
const content = await file.text();
User Events
Handle user interactions
button.addEventListener('click', async () => {
await handleClick();
});
🔹 Fetch API - Modern HTTP Requests
The Fetch API provides a modern way to make HTTP requests:
// Basic GET request
async function getUsers() {
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
console.log("Users:", users);
return users;
} catch (error) {
console.error("Failed to fetch users:", error);
return [];
}
}
// POST request with data
async function createUser(userData) {
try {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
const newUser = await response.json();
console.log("Created user:", newUser);
return newUser;
} catch (error) {
console.error("Failed to create user:", error);
}
}
// Usage
getUsers();
createUser({ name: "John Doe", email: "[email protected]" });
Output:
Users: [{id: 1, name: "Alice"}, {id: 2, name: "Bob"}]
Created user: {id: 3, name: "John Doe", email: "[email protected]"}
🔹 Timer Functions
Control timing and scheduling of operations:
// setTimeout - run once after delay
const timeoutId = setTimeout(() => {
console.log("This runs after 3 seconds");
}, 3000);
// Clear timeout if needed
// clearTimeout(timeoutId);
// setInterval - run repeatedly
const intervalId = setInterval(() => {
console.log("This runs every 2 seconds");
}, 2000);
// Clear interval after 10 seconds
setTimeout(() => {
clearInterval(intervalId);
console.log("Interval cleared");
}, 10000);
// Promise-based delay function
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Usage with async/await
async function delayedOperation() {
console.log("Starting operation...");
await delay(2000);
console.log("Operation completed after 2 seconds");
}
delayedOperation();
Output Timeline:
Starting operation... (immediately)
This runs every 2 seconds (at 2s, 4s, 6s, 8s)
Operation completed after 2 seconds (at 2s)
This runs after 3 seconds (at 3s)
Interval cleared (at 10s)
🔹 File and Data Loading
Load and process files asynchronously:
// Load JSON data
async function loadConfig() {
try {
const response = await fetch('/config.json');
const config = await response.json();
console.log("Config loaded:", config);
return config;
} catch (error) {
console.error("Failed to load config:", error);
return { theme: 'default', language: 'en' }; // fallback
}
}
// Load text file
async function loadTextFile(filename) {
try {
const response = await fetch(filename);
const text = await response.text();
console.log(`Loaded ${filename}:`, text.substring(0, 100) + "...");
return text;
} catch (error) {
console.error(`Failed to load ${filename}:`, error);
return "";
}
}
// Load image with Promise
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
console.log(`Image loaded: ${src}`);
resolve(img);
};
img.onerror = () => {
console.error(`Failed to load image: ${src}`);
reject(new Error(`Image load failed: ${src}`));
};
img.src = src;
});
}
// Usage
async function initializeApp() {
const config = await loadConfig();
const readme = await loadTextFile('/README.txt');
const logo = await loadImage('/logo.png');
console.log("App initialized with all resources");
}
initializeApp();
Output:
Config loaded: {theme: "dark", language: "en"}
Loaded /README.txt: Welcome to our application...
Image loaded: /logo.png
App initialized with all resources
🔹 Event-Driven Async Operations
Handle user interactions and system events asynchronously:
// Async event handlers
class AsyncButton {
constructor(element) {
this.element = element;
this.loading = false;
this.setupEventListeners();
}
setupEventListeners() {
this.element.addEventListener('click', async (event) => {
if (this.loading) return; // Prevent double-clicks
this.loading = true;
this.element.disabled = true;
this.element.textContent = 'Loading...';
try {
await this.handleClick(event);
} catch (error) {
console.error('Button click failed:', error);
alert('Operation failed. Please try again.');
} finally {
this.loading = false;
this.element.disabled = false;
this.element.textContent = 'Click Me';
}
});
}
async handleClick(event) {
// Simulate async operation
await new Promise(resolve => setTimeout(resolve, 2000));
console.log('Async operation completed!');
}
}
// Form submission with async validation
async function handleFormSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
try {
// Validate data asynchronously
await validateFormData(data);
// Submit to server
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (response.ok) {
console.log('Form submitted successfully!');
}
} catch (error) {
console.error('Form submission failed:', error);
}
}
async function validateFormData(data) {
// Simulate async validation (e.g., check if email exists)
await new Promise(resolve => setTimeout(resolve, 500));
if (!data.email.includes('@')) {
throw new Error('Invalid email format');
}
}
// Usage
const button = document.querySelector('#async-button');
new AsyncButton(button);
const form = document.querySelector('#async-form');
form.addEventListener('submit', handleFormSubmit);
Behavior:
• Button shows "Loading..." during async operation
• Form validates data before submission
• Prevents double-clicks and multiple submissions
• Handles errors gracefully with user feedback