> Как реализовать функцию promisify в JavaScript (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: циан
Стек: JavaScript
> Пример ответа
Короткий ответ
promisify - это функция-утилита, которая преобразует функцию с callback-стилем (например, (err, result) => {}) в функцию, возвращающую Promise. Реализация оборачивает вызов исходной функции и в колбэке либо резолвит промис с результатом, либо реджектит с ошибкой. В Node.js есть встроенный util.promisify, но для браузера или кастомных случаев пишут свою реализацию. Ключевой момент - корректно пробросить this и аргументы, а также учесть колбэки с несколькими результатами.
Подробное объяснение
Callback-стиль в JavaScript - это соглашение, где последний аргумент функции - колбэк, вызываемый с первым аргументом-ошибкой (или null) и затем результатами. promisify создаёт новую функцию, которая принимает те же аргументы, но вместо колбэка возвращает Promise.
Базовая реализация:
- возвращаем функцию, которая принимает
...argsи возвращаетnew Promise - внутри промиса вызываем исходную функцию с
...argsи добавляем в конец колбэк - в колбэке проверяем
err- если есть, вызываемreject(err), иначеresolve(result)
Важные нюансы:
- контекст
this: если исходная функция вызывается как метод объекта, нужно сохранитьthisчерезFunction.prototype.callилиapply - несколько результатов: некоторые колбэки передают более одного результата (например,
fs.readdir-(err, files)), но бывают и(err, result1, result2)- тогда нужно резолвить массив или объект - сигнатура колбэка: не все функции следуют Node.js соглашению (первый аргумент - ошибка), поэтому иногда нужна опция для кастомного колбэка
- обработка ошибок синхронного выброса: если исходная функция бросает исключение до вызова колбэка, его нужно поймать и отклонить промис
В Node.js util.promisify дополнительно поддерживает символ util.promisify.custom для переопределения поведения и обрабатывает колбэки с несколькими аргументами через resolve с массивом.
На практике
На собеседовании важно показать понимание не только базовой механики, но и edge cases. Обычно просят написать реализацию, затем задают вопросы про this, множественные результаты и совместимость с Node.js API.
Практические сценарии:
- обёртка для старых API, которые используют колбэки (например,
XMLHttpRequest, IndexedDB, старые библиотеки) - унификация асинхронного кода в проекте, где уже используются async/await
- тестирование: promisify позволяет писать тесты на основе промисов вместо колбэков
Хорошая реализация должна быть компактной, но покрывать основные случаи. Не нужно переусложнять - интервьюер оценит ясность и внимание к деталям.
Пример кода
JAVASCRIPTfunction promisify(fn) {return function(...args) {return new Promise((resolve, reject) => {const callback = (err, ...results) => {if (err) {reject(err);} else {resolve(results.length > 1 ? results : results[0]);}};try {fn.call(this, ...args, callback);} catch (error) {reject(error);}});};}// пример использованияconst fs = require('fs');const readFile = promisify(fs.readFile);readFile('file.txt', 'utf8').then(data => console.log(data)).catch(err => console.error(err));
Как отвечать на собеседовании
Начни с краткого определения и назначения. Затем покажи базовую реализацию на доске или в коде. Обязательно упомяни:
- почему нужна проверка
errпервым аргументом - как обрабатывается
this(черезfn.call(this, ...)) - что делать с несколькими результатами колбэка
- отличие от встроенного
util.promisify(поддержкаcustomсимвола, обработка нескольких аргументов)
Если спросят про edge cases - расскажи про синхронные исключения и про то, что колбэк может быть вызван асинхронно, но это не влияет на промис. Не углубляйся в микрооптимизации, если не просят.
Что проверяет интервьюер
- понимание асинхронности и промисов
- знание callback-конвенции в Node.js
- умение работать с
thisи аргументами функций - внимание к деталям (обработка ошибок, множественные результаты)
- способность писать чистый и лаконичный код
Типичные ошибки
- забывают про
this- если функция вызывается как метод, контекст теряется - не обрабатывают синхронные исключения исходной функции
- резолвят только первый результат, игнорируя дополнительные аргументы колбэка
- не проверяют, что колбэк вызывается ровно один раз (в реальности это редкость, но стоит упомянуть)
- переусложняют реализацию, добавляя лишние проверки, которые не нужны для базового случая
> Похожие задачи по frontend
Можно ли создать функцию для запроса продуктов, которая возвращает промис
Как реализовать таймаут с abort для запроса в JavaScript
В чем разница каррирования и частичного применения в JavaScript
Можно ли пометить стрелочную функцию как асинхронную в JavaScript
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью