Функції зворотного виклику та пекло зворотних викликів у JavaScript
Що таке Callback Функція?
Callback — це функція, яка передається як аргумент до іншої функції і викликається пізніше (повертається назад), коли завершено певне завдання або виконана умова.
Основний Приклад
function greet(name, callback) {
const message = `Hello, ${name}!`;
callback(message);
}
greet("Alice", (msg) => console.log(msg));
// "Hello, Alice!"Синхронні Callback-и
Використовуються в методах масивів та ітерації:
const numbers = [1, 2, 3, 4, 5];
// forEach callback
numbers.forEach((num) => console.log(num));
// map callback
const doubled = numbers.map((num) => num * 2);
// filter callback
const evens = numbers.filter((num) => num % 2 === 0);
// sort callback
const sorted = numbers.sort((a, b) => a - b);Асинхронні Callback-и
Використовуються для операцій, які займають час:
// setTimeout
setTimeout(() => {
console.log("Виконано через 1 секунду");
}, 1000);
// Обробники подій
button.addEventListener("click", (event) => {
console.log("Кнопка натиснута!", event.target);
});
// Читання файлів (Node.js)
fs.readFile("data.txt", "utf8", (error, data) => {
if (error) {
console.error("Помилка:", error);
return;
}
console.log(data);
});Патерн Callback з Помилкою на Першому Місці
Конвенція Node.js — перший параметр завжди є помилкою:
function fetchData(url, callback) {
// callback(error, data)
try {
const data = /* ... отримати дані ... */;
callback(null, data); // Успіх: помилка null
} catch (error) {
callback(error, null); // Невдача: передати помилку
}
}
fetchData("/api/users", (error, data) => {
if (error) {
console.error("Не вдалося:", error);
return;
}
console.log("Дані:", data);
});Callback Hell (Піраміда Погибелі)
Коли кілька асинхронних операцій залежать одна від одної, callback-и глибоко вкладені:
// ❌ Callback Hell
getUser(userId, (err, user) => {
if (err) return handleError(err);
getOrders(user.id, (err, orders) => {
if (err) return handleError(err);
getOrderDetails(orders[0].id, (err, details) => {
if (err) return handleError(err);
getShippingInfo(details.shipId, (err, shipping) => {
if (err) return handleError(err);
console.log(shipping);
});
});
});
});Рішення для Callback Hell
1. Проміси
getUser(userId)
.then(user => getOrders(user.id))
.then(orders => getOrderDetails(orders[0].id))
.then(details => getShippingInfo(details.shipId))
.then(shipping => console.log(shipping))
.catch(handleError);2. async/await
async function getShipping(userId) {
const user = await getUser(userId);
const orders = await getOrders(user.id);
const details = await getOrderDetails(orders[0].id);
const shipping = await getShippingInfo(details.shipId);
return shipping;
}3. Іменовані Функції
function handleUser(err, user) {
if (err) return handleError(err);
getOrders(user.id, handleOrders);
}
function handleOrders(err, orders) {
if (err) return handleError(err);
getOrderDetails(orders[0].id, handleDetails);
}Важливо:
Callback-и є основою асинхронного JavaScript. Однак, для складних асинхронних потоків, віддавайте перевагу Promises або async/await замість глибоко вкладених callback-ів. Методи масивів, такі як map, filter, reduce, використовують синхронні callback-и і є цілком прийнятними.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.