> Как создать и выполнить промис через конструктор в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: TYMY
Стек: JavaScript
> Пример ответа
Короткий ответ
Конструктор new Promise(executor) принимает функцию-исполнитель с двумя параметрами - resolve и reject. Вызов resolve(value) переводит промис в состояние fulfilled, reject(error) - в rejected. Промис выполняется сразу при создании, асинхронно вызывая then/catch в microtask queue. Для отложенного выполнения executor может содержать асинхронные операции (setTimeout, fetch, I/O).
Подробное объяснение
Конструктор Promise - это базовый механизм создания промисов в JavaScript. Функция executor вызывается синхронно в момент создания промиса, что позволяет инициировать асинхронную операцию. Параметры resolve и reject - это функции обратного вызова, предоставляемые средой выполнения.
resolve(value) завершает промис успешно, передавая значение в цепочку .then(). Если передать другой промис, он будет "развёрнут" - итоговый промис примет состояние переданного. reject(reason) завершает промис с ошибкой, передавая причину в .catch() или второй аргумент .then().
Важно: вызов resolve или reject после первого не имеет эффекта - промис может быть завершён только один раз. Остальной код в executor продолжает выполняться, но его результаты игнорируются. Для асинхронных операций (например, setTimeout) executor завершается до вызова resolve/reject, что является нормой.
На практике
Создание промиса через конструктор обычно требуется при обёртывании колбэк-ориентированных API (например, fs.readFile в Node.js, XMLHttpRequest в браузере). В современном коде предпочтительнее использовать async/await и встроенные промис-обёртки, но понимание конструктора критично для отладки и работы с legacy-кодом.
Типичный паттерн - обёртка функции с колбэком: new Promise((resolve, reject) => { someAsyncFunction(args, (err, data) => { if (err) reject(err); else resolve(data); }); }). При этом нужно обрабатывать ошибки синхронного кода внутри executor - если executor бросает исключение до вызова resolve/reject, промис автоматически переходит в rejected.
Пример кода
JAVASCRIPT// Базовое создание и выполнениеconst promise = new Promise((resolve, reject) => {const success = Math.random() > 0.5;setTimeout(() => {if (success) {resolve('Успех');} else {reject(new Error('Ошибка'));}}, 1000);});promise.then(result => console.log(result)).catch(error => console.error(error.message));// Обёртка колбэка (Node.js стиль)const fs = require('fs');function readFilePromise(path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf8', (err, data) => {if (err) reject(err);else resolve(data);});});}// Важно: executor выполняется синхронноconsole.log('Старт');new Promise((resolve) => {console.log('Внутри executor');resolve('Готово');}).then(console.log);console.log('Финиш');// Вывод: Старт, Внутри executor, Финиш, Готово
Как отвечать на собеседовании
Начни с определения конструктора и его параметров. Объясни, что executor выполняется синхронно, а resolve/reject - асинхронно через microtask queue. Упомяни однократность завершения и "тихие" ошибки в executor (если не вызван reject). Приведи пример обёртки колбэка. Для senior-уровня добавь про разворачивание промисов при передаче в resolve и про то, что executor может быть асинхронным сам по себе (async-функция не рекомендуется, но возможна).
Что проверяет интервьюер
- Понимание синхронного выполнения executor и асинхронного вызова then/catch.
- Знание, что промис может быть завершён только один раз.
- Умение обёртывать колбэк-ориентированные API.
- Понимание разницы между microtask и macrotask (event loop).
- Осведомлённость о "тихих" ошибках и необходимости try-catch внутри executor.
Типичные ошибки
- Вызов resolve/reject несколько раз (работает только первый).
- Забывание вызвать reject при ошибке в колбэке - промис остаётся в pending.
- Использование async-функции как executor без обработки ошибок (async-функция возвращает промис, который не будет перехвачен конструктором).
- Предположение, что executor выполняется асинхронно - на самом деле он синхронный.
- Необработка синхронных исключений внутри executor (они автоматически переводят промис в rejected, но только если не было вызова resolve до них).
> Похожие задачи по frontend
Как создать массив с числами от 1 до 50 и вывести их в JavaScript?
Для чего нужен тип Symbol в JavaScript?
Как реализовать бесконечный скролл
Как избежать конкатенации чисел как строк в функции суммы аргументов в JavaScript?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью