В чем проблема использования колбэков в JavaScript
Что проверяют
Понимаете ли вы, почему индустрия ушла от колбэков к промисам, и можете ли назвать проблемы глубже, чем «вложенность некрасивая». Следом обычно просят переписать пример на async/await или объяснить, почему try/catch не ловит ошибку внутри колбэка.
Как отвечать
Сначала уточните, что колбэк сам по себе не зло: array.map, addEventListener, обработчики событий в React это тоже колбэки, и с ними всё в порядке. Проблемы начинаются, когда колбэками выражают цепочку асинхронных операций.
- вложенность: каждая следующая операция уходит на уровень глубже, логику приходится читать лесенкой;
- обработка ошибок: исключение, брошенное в асинхронном колбэке, не долетит до внешнего
try/catch, к этому моменту тот фрейм уже завершился. Отсюда соглашение Node.js(err, data) => {}и проверкаerrна каждом уровне; - инверсия управления: вы отдаёте продолжение своей программы чужому коду, а он может вызвать колбэк дважды, ни разу, синхронно или асинхронно. Промис от этого защищает: он разрешается один раз, а обработчик
.thenвсегда выполняется асинхронно, через очередь микрозадач; - композиция: дождаться трёх запросов параллельно, взять первый ответ или отменить операцию на колбэках приходится вручную, счётчиками и флагами. Для промисов есть
Promise.all,Promise.allSettled,Promise.race,Promise.any, а отмену даётAbortController, который понимаетfetch.
Закончите тем, что async/await это синтаксис поверх промисов: код выглядит последовательным, и обычный try/catch снова работает. Старые API на колбэках оборачиваются в new Promise или через util.promisify в Node.js.
Где спотыкаются
Говорят, что колбэки плохи вообще. Интервьюер тут же спросит про map и обработчики событий, и ответ рассыплется.
Считают, что колбэк-ад замедляет приложение. Проблема в сопровождаемости и обработке ошибок, скорость выполнения тут почти ни при чём.
Пишут await внутри цикла там, где запросы независимы, и превращают параллельную загрузку в последовательную. Независимые операции собирают через Promise.all, а для забытых catch в браузере есть событие unhandledrejection, которое стоит логировать.