Асинхронный JavaScript: ключевые конструкции для прохождения интервью
Основные асинхронные механизмы
Почему в JavaScript требуется асинхронное выполнение?
JavaScript выполняется в одном потоке, использующем Event Loop. Долгие операции (запросы к серверу, таймеры, чтение файлов) блокировали бы поток, поэтому они выполняются асинхронно. Базовые подходы: колбэки, Promise, async/await.
Как реализовать асинхронность с помощью колбэков?
Колбэк - функция, переданная в другую функцию и вызываемая после завершения асинхронной операции.
setTimeout(() => { console.log('Выполнено'); }, 1000);Js вопросы (вопросы по javascript для собеседования)
Цель: обработка результата после задержки. Используется в старых API (например, fs.readFile в Node.js).
Проблема: Callback hell - вложенные колбэки усложняют читаемость. Также трудно обрабатывать ошибки централизованно. Пример ошибки: забыть проверить первый аргумент (err) приводит к необработанным исключениям.
Как упростить асинхронный код с Promise?
Promise - объект, представляющий результат асинхронной операции. Позволяет цепочки .then() и .catch().
fetch('/data').then(response => response.json()).then(data => console.log(data)).catch(error => console.error(error));Цель: избежать вложенности, улучшить обработку ошибок. Используется в современных API.
Проблема: Если забыть return в .then(), цепочка нарушается. Необработанные исключения в Promise (без .catch) приводят к игнорированию ошибок. Также сложно отменить Promise.
Как сделать асинхронный код похожим на синхронный с async/await?
async/await - синтаксический сахар над Promise. Функция с async возвращает Promise, await приостанавливает выполнение до разрешения.
async function getData() { try { const response = await fetch('/data'); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } }Цель: линейный код без цепочек, упрощение отладки. Поддерживает try/catch.
Проблема: await блокирует выполнение внутри async функции, но не блокирует поток. Частая ошибка - забыть try/catch или использовать await в цикле последовательно там, где можно параллельно (Promise.all). Также async функции всегда возвращают Promise, что может быть неочевидно.
Расширенные примеры асинхронных паттернов
Пример колбэка с обработкой ошибки и демонстрация callback hell:
// Пример колбэка с проверкой ошибки
function loadUser(id, callback) {
setTimeout(() => {
if (id <= 0) {
callback(new Error('Invalid id'), null);
} else {
callback(null, { id, name: 'User' + id });
}
}, 100);
}
// Использование
loadUser(1, (err, user) => {
if (err) return console.error(err);
console.log(user.name);
});// Результат: User1
Пример цепочки Promise с параллельным выполнением:
const urls = ['/api/1', '/api/2', '/api/3'];
Promise.all(urls.map(url => fetch(url).then(res => res.json())))
.then(results => console.log(results))
.catch(err => console.error('Ошибка:', err));// Результат: [данные1, данные2, данные3]
Пример async/await с параллельным выполнением через Promise.all:
async function fetchAllUrls(urls) {
try {
const promises = urls.map(url => fetch(url).then(res => res.json()));
const results = await Promise.all(promises);
console.log(results);
} catch (err) {
console.error('Ошибка:', err);
}
}// Результат: [данные1, данные2, данные3]
Пример обработки ошибок в Promise с использованием finally:
fetch('/data')
.then(data => data.json())
.catch(err => console.error('Fetch error:', err))
.finally(() => console.log('Завершено'));// Результат: 'Завершено' появляется независимо от успеха/ошибки
Пример использования Promise.race для временной защиты:
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000));
const request = fetch('/slow-endpoint');
Promise.race([request, timeout])
.then(response => console.log(response))
.catch(err => console.error(err.message));// Если запрос дольше 5 секунд, получим 'Timeout'
Пример генератора (устаревший, но возможный подход) с использованием co:
// Для демонстрации, не рекомендуется в современном коде
function* gen() {
const data = yield fetch('/data').then(r => r.json());
console.log(data);
}
// Используется библиотека co или ручная обертка// Результат: требует внешнего выполнения