Въведение в асинхронния JavaScript
JavaScript е single-threaded, но Event Loop му позволява да обработва асинхронни операции ефективно. Разбирането на тези концепции е критично за всеки frontend разработчик.
Event Loop визуализация
┌─────────────────────────────────────────────────────────────────────────────┐
│ JAVASCRIPT EVENT LOOP │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Call Stack │ ◄── Изпълнява се синхронен код │
│ │ │ │
│ │ function() │ │
│ │ main() │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Microtask │ ──► │ Render │ ──► │ Macrotask │ │
│ │ Queue │ │ (if needed) │ │ Queue │ │
│ │ │ │ │ │ │ │
│ │ - Promises │ │ - Style calc │ │ - setTimeout │ │
│ │ - queueMicro │ │ - Layout │ │ - setInterval │ │
│ │ - MutationObs │ │ - Paint │ │ - I/O events │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ Приоритет: Microtasks > Render > Macrotasks │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Callbacks (старият начин)
// Callback hell
getUser(userId, (user) => {
getOrders(user.id, (orders) => {
getOrderDetails(orders[0].id, (details) => {
console.log(details);
});
});
});
Promises
// Promise states: pending → fulfilled/rejected
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('Data loaded!');
} else {
reject(new Error('Failed to load'));
}
}, 1000);
});
// Consuming promises
promise
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => console.log('Done'));
Promise combinators
// Promise.all - всички трябва да успеят
const [users, products] = await Promise.all([
fetch('/api/users'),
fetch('/api/products')
]);
// Promise.allSettled - чака всички, независимо от резултата
const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(r => {
if (r.status === 'fulfilled') console.log(r.value);
else console.error(r.reason);
});
// Promise.race - първият който завърши
const fastest = await Promise.race([p1, p2, p3]);
// Promise.any - първият който успее
const firstSuccess = await Promise.any([p1, p2, p3]);
Async/Await
async function fetchUserData(userId) {
try {
const user = await getUser(userId);
const orders = await getOrders(user.id);
const details = await getOrderDetails(orders[0].id);
return details;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// Паралелно изпълнение
async function fetchAllData() {
const [users, products, orders] = await Promise.all([
fetchUsers(),
fetchProducts(),
fetchOrders()
]);
return { users, products, orders };
}
AbortController
const controller = new AbortController();
async function fetchWithTimeout(url, timeout = 5000) {
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
return response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request timed out');
}
throw error;
}
}
Error Handling Patterns
// Wrapper function
async function safeAsync(promise) {
try {
const data = await promise;
return [data, null];
} catch (error) {
return [null, error];
}
}
// Usage
const [user, error] = await safeAsync(fetchUser(id));
if (error) {
handleError(error);
return;
}
console.log(user);
Заключение
Разбирането на асинхронния JavaScript е фундаментално за модерната уеб разработка. Използвайте async/await за четим код, Promise combinators за паралелни операции и AbortController за timeout management.
Брой думи: 3,145