Как создать собственную функцию executor в Promise в JavaScript
Что проверяют
Понимаете ли вы, как устроен конструктор Promise: когда вызывается executor, что происходит с исключением внутри него и почему повторный resolve ничего не меняет. Иногда вопрос перерастает в просьбу написать упрощённый MyPromise с цепочкой then.
Как отвечать
Executor это функция, которую вы передаёте в new Promise((resolve, reject) => { ... }). Правила её поведения:
- вызывается синхронно: сразу в конструкторе, до того как
new Promiseвернёт объект; - исключение: если executor синхронно бросил ошибку, промис переходит в
rejected; - однократность: считается только первый вызов
resolveилиreject, остальные игнорируются; - thenable:
resolve(otherPromise)не кладёт промис внутрь, а перенимает его состояние; - возвращаемое значение: то, что вернул executor, игнорируется.
Типичное применение на фронтенде это обёртка над колбэчным API: img.onload и img.onerror, FileReader, setTimeout для функции sleep(ms). Если resolve нужен снаружи, есть Promise.withResolvers() из ES2024: он возвращает промис вместе с resolve и reject.
Если просят свою реализацию, назовите главное: then возвращает новый промис, обработчики запускаются асинхронно через queueMicrotask, а значение, которое вернул обработчик, разрешает следующий промис в цепочке. Без этого .then().catch() просто не заработает.
Где спотыкаются
Думают, что встроенный перехват ошибок в executor ловит всё. Ошибка, брошенная внутри setTimeout в executor, до промиса не долетит: промис навсегда останется в pending, а ошибка уйдёт в глобальный обработчик. Внутри асинхронных колбэков нужно явно вызывать reject.
Пишут new Promise(async (resolve) => { ... }). Ошибка внутри async-функции не отклоняет внешний промис, и ESLint ругается на такое правилом no-async-promise-executor.
Оборачивают в new Promise то, что уже возвращает промис, например fetch. Получается лишний слой, где легко забыть reject и проглотить ошибку. Верните сам fetch(...) или используйте async/await.