Когда вызывается колбэк в JavaScript и что его триггерит
Что проверяют
Понимаете ли вы разницу между синхронным и асинхронным колбэком и как работает event loop: кто ставит колбэк в очередь и когда он реально выполнится. Следом обычно дают задачку на порядок вывода с setTimeout и Promise.
Как отвечать
Колбэк это функция, которую передаёте вы, а вызывает кто-то другой. Важно, кто и когда:
- синхронно:
map,forEach, компаратор вsort, исполнитель вnew Promise(executor). Колбэк отработает сразу, до следующей строки; - задача (macrotask):
setTimeoutиsetInterval, события пользователя, сетевые ответы,postMessage. Триггер здесь среда: браузер отсчитал таймер или получил клик и поставил задачу в очередь; - микрозадача: обработчики
.then,.catch,.finally, продолжение послеawait,queueMicrotask,MutationObserver.
Event loop берёт одну задачу, выполняет её до конца, затем полностью опустошает очередь микрозадач, и только после этого браузер может отрисовать кадр. Колбэки requestAnimationFrame идут перед отрисовкой. Отсюда классика:
console.log(1);
setTimeout(() => console.log(2));
Promise.resolve().then(() => console.log(3));
console.log(4);
// 1, 4, 3, 2setTimeout(fn, 0) не значит «немедленно»: колбэк ждёт, пока освободится стек и отработают микрозадачи, у глубоко вложенных таймеров есть минимальная задержка, а в фоновых вкладках браузер их сильно замедляет.
Глубоко вложенные колбэки дают callback hell, поэтому асинхронный код сейчас пишут на промисах и async/await.
Где спотыкаются
Считают, что любой колбэк асинхронный. Колбэк map и исполнитель промиса синхронны, а el.dispatchEvent() и el.click() вызывают обработчики сразу, в отличие от настоящего клика.
Оборачивают setTimeout в try/catch и ждут, что ошибка из колбэка поймается. К моменту вызова колбэка блока try на стеке уже нет.
Теряют this, передавая метод как колбэк: button.addEventListener("click", obj.handle) вызовет handle с this, равным кнопке. Нужна стрелочная функция или bind.