Как создать и выполнить промис через конструктор в JavaScript
Что проверяют
Понимаете ли вы, как промис устроен изнутри: когда выполняется executor, что будет при повторном resolve и при исключении. Следом просят обернуть в промис API на колбэках или предсказать порядок вывода в консоль.
Как отвечать
new Promise(executor) принимает функцию с двумя аргументами, resolve и reject. Главное, что стоит сказать сразу:
- executor синхронный: он вызывается немедленно, прямо внутри конструктора. Всё, что в нём написано синхронно, отработает раньше строки, следующей за
new Promise; - состояние меняется один раз: из
pendingвfulfilledилиrejected. Повторныйresolveилиrejectпосле этого молча игнорируется; - исключение внутри executor: превращается в
reject, но только если брошено синхронно. Ошибка внутриsetTimeoutв executor уже не поймается, её нужно передать вrejectявно; resolveс другим промисом или thenable: внешний промис принимает его состояние, а не заворачивает промис в значение;- обработчики
.thenи.catch: всегда асинхронные, попадают в очередь микрозадач даже для уже выполненного промиса.
Практический смысл конструктора в промисификации: setTimeout, FileReader, img.onload, события сокета. Например, const delay = ms => new Promise(r => setTimeout(r, ms)). Отклонять стоит объектом Error, а не строкой, иначе теряется стек. Если нужно вынести resolve наружу, в современных браузерах есть Promise.withResolvers().
Где спотыкаются
Оборачивают в new Promise то, что уже возвращает промис, например fetch. Это лишний код, и ошибки часто теряются, потому что в catch забыли вызвать reject.
Думают, что executor выполнится позже, асинхронно. Из-за этого неверно отвечают на задачи про порядок console.log.
Оставляют промис без .catch или await без try/catch. В браузере это событие unhandledrejection, в Node.js по умолчанию падение процесса.