> В каком порядке выполняются промисы и их обработчики then/catch в JavaScript и как это влияет на порядок ошибок? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Яндекс
Стек: JavaScript
> Пример ответа
Короткий ответ
Промисы выполняются в порядке их создания, а обработчики then/catch - в порядке их прикрепления, но только после завершения текущего синхронного кода и микротасков. Ошибка в промисе перехватывается ближайшим catch в цепочке, при этом дальнейшие then/catch выполняются в зависимости от того, как обработана ошибка. Порядок ошибок определяется последовательностью промисов и их обработчиков в цепочке.
Подробное объяснение
Промисы и их обработчики (then/catch) работают в рамках event loop. Когда промис создаётся, его executor выполняется синхронно. Асинхронная часть (например, resolve/reject) попадает в очередь микротасков. Обработчики then/catch тоже становятся микротасками, которые выполняются после завершения текущего макрозадачи (например, после выполнения всего синхронного кода).
Порядок выполнения:
- Синхронный код (включая executor промиса).
- Микротаски: все обработчики then/catch, которые уже прикреплены к разрешённым промисам.
- Макрозадачи (setTimeout, setInterval) и так далее.
Если промис отклонён (rejected), то управление передаётся ближайшему catch в цепочке. Если catch обрабатывает ошибку и возвращает значение, следующие then получают это значение. Если catch не обрабатывает ошибку (или пробрасывает её дальше), ошибка идёт по цепочке до следующего catch.
Порядок ошибок зависит от того, как построена цепочка: если несколько промисов запущены параллельно (например, через Promise.all), ошибка первого отклонённого промиса определяет результат всего Promise.all. В последовательной цепочке ошибка прерывает выполнение последующих then, если не перехвачена.
На практике
На практике важно помнить, что then/catch не блокируют выполнение друг друга - они просто регистрируют колбэки. Если у вас есть несколько промисов, созданных одновременно, их обработчики выполнятся в порядке разрешения промисов, но все они будут обработаны до следующей макрозадачи.
Пример: если вы создаёте два промиса с setTimeout(0), их then/catch выполнятся после всех синхронных операций, но порядок внутри микротасков будет соответствовать порядку разрешения промисов (первый разрешённый - первый обработанный).
Ошибки в цепочке: если catch возвращает новое значение, цепочка продолжается. Если catch пробрасывает ошибку (throw или return Promise.reject), следующий catch перехватит её. Это позволяет строить гибкие обработчики ошибок, но требует аккуратности, чтобы не потерять ошибку.
Пример кода
JAVASCRIPTconsole.log('1: sync start');const promise1 = new Promise((resolve) => {console.log('2: executor promise1');resolve('A');});const promise2 = new Promise((_, reject) => {console.log('3: executor promise2');reject('Error B');});promise1.then((val) => {console.log('4: then promise1', val);return val + '!';}).catch((err) => {console.log('5: catch promise1', err);});promise2.catch((err) => {console.log('6: catch promise2', err);return 'Recovered';}).then((val) => {console.log('7: then after catch', val);});console.log('8: sync end');// Вывод:// 1: sync start// 2: executor promise1// 3: executor promise2// 8: sync end// 4: then promise1 A// 6: catch promise2 Error B// 7: then after catch Recovered
Обратите внимание: catch для promise2 выполняется до then после catch, так как catch перехватывает ошибку и возвращает значение, которое затем передаётся в следующий then.
Как отвечать на собеседовании
Начни с краткого определения: промисы и их обработчики - это микротаски, которые выполняются после синхронного кода. Объясни порядок: сначала executor промиса (синхронно), затем все then/catch в порядке их прикрепления к разрешённым промисам. Упомяни, что ошибка перехватывается ближайшим catch, и если catch не пробрасывает ошибку, цепочка продолжается. Приведи пример с параллельными промисами (Promise.all) и последовательной цепочкой. Подчеркни, что порядок ошибок зависит от того, как построена цепочка и как обрабатываются ошибки.
Что проверяет интервьюер
Интервьюер проверяет понимание event loop, очереди микротасков, разницу между синхронным и асинхронным выполнением, а также умение предсказывать порядок выполнения в сложных цепочках промисов. Также оценивается знание обработки ошибок: как catch влияет на дальнейшее выполнение, что происходит при пробросе ошибки.
Типичные ошибки
- Путать порядок выполнения: думать, что then выполняется сразу после resolve, а не после синхронного кода.
- Не учитывать, что catch перехватывает только ошибки, возникшие до него в цепочке.
- Думать, что ошибка в промисе автоматически останавливает все остальные промисы (это не так, если они не связаны через Promise.all или цепочку).
- Забывать, что then/catch возвращают новый промис, и цепочка может продолжаться после catch.
> Похожие задачи по frontend
Почему нельзя просто вернуть Promise.resolve с промисом внутри в реализации any?
Как определить момент завершения всех промисов с ошибками для вызова reject в JavaScript?
Как обработать успешное разрешение одного из промисов в функции any?
Почему нельзя использовать forEach для реализации some с прерыванием?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью