В какой момент вызывается callback в конструкторе Promise в JavaScript
Что проверяют
Понимаете ли вы, что промис асинхронен не весь. Функция, переданная в конструктор, выполняется синхронно, и об этом спотыкается большинство.
Как отвечать
Исполнитель, то есть функция (resolve, reject) => { ... }, вызывается немедленно и синхронно, прямо в момент new Promise(...), до того как конструктор вернёт объект. Асинхронными являются только обработчики then, catch и finally: они попадают в очередь микрозадач и запускаются после того, как опустеет стек вызовов.
console.log("1");
const p = new Promise((resolve) => {
console.log("2"); // выполнится сразу
resolve("значение");
});
p.then((v) => console.log("4", v)); // микрозадача
console.log("3");
// порядок: 1, 2, 3, 4Отсюда следствия, которые стоит проговорить:
- вызов
resolveне прерывает исполнитель: код после него продолжит выполняться, поэтому обычно пишутreturn resolve(...); - промис уже разрешён к моменту подписки, и
thenвсё равно выполнится асинхронно, а не мгновенно; - ошибка, брошенная синхронно внутри исполнителя, превращается в отклонение промиса, но ошибка, брошенная в асинхронном колбэке внутри него, туда не попадёт;
- повторные вызовы
resolveилиrejectигнорируются: состояние меняется один раз.
Полезно добавить, что в конструктор оборачивают колбэчные API (таймеры, старые библиотеки), а если функция уже возвращает промис, оборачивать её ещё раз не нужно.
Где спотыкаются
Ожидают, что тело конструктора выполнится позже, и удивляются порядку вывода.
Считают, что await перед уже разрешённым промисом ничего не стоит: продолжение всё равно уходит в микрозадачу.
Ловят ошибку из setTimeout внутри исполнителя через catch промиса. Она туда не попадёт, отклонять нужно явным reject.