Как правильно реализовать вызов функции с передачей аргументов и вызовом колбэка после выполнения
Что проверяют
Понимаете ли вы функции как значения в JavaScript и умеете ли обращаться с колбэком аккуратно: вызвать ровно один раз, с правильным this и с передачей ошибки. Следом обычно просят переписать то же на промисах или async/await.
Как отвечать
Базовая форма простая: функция принимает аргументы и последним параметром колбэк, а после работы вызывает его с результатом. Для обобщённой обёртки пригодятся rest-параметры: function run(fn, args, cb) { ... fn(...args) ... }. Если нужен контекст, есть fn.call(ctx, a, b), fn.apply(ctx, args) или заранее привязанный fn.bind(ctx).
Дальше покажите, что знаете соглашения:
- error-first: колбэк получает
(err, result), как принято в Node.js. Ошибка первым аргументом,null, если всё прошло; - ровно один вызов: колбэк не вызывается дважды и не теряется ни в одной ветке, включая исключение;
- одинаковая асинхронность: функция либо всегда вызывает колбэк синхронно, либо всегда асинхронно. Иначе код после вызова ведёт себя по-разному. Если результат готов сразу, отложите вызов через
queueMicrotask; - поддержка промисов:
Promise.resolve(fn(...args)).then(r => cb(null, r), e => cb(e))одинаково обработает и обычную функцию, и асинхронную. Синхронное исключение изfnпри этом нужно отдельно обернуть вtry.
Завершите современным вариантом: колбэк легко превращается в промис через new Promise((resolve, reject) => fn(...args, (err, r) => err ? reject(err) : resolve(r))), а в Node.js для этого есть util.promisify. Вложенные колбэки заменяются цепочкой await, и ошибки ловятся одним try/catch.
Где спотыкаются
Вызывают колбэк внутри try вместе с основной работой. Если исключение бросил сам колбэк, catch вызывает его второй раз, уже с ошибкой, и обработчик отрабатывает дважды.
Передают метод объекта как obj.save и теряют this: внутри колбэка он равен undefined в строгом режиме. Нужна стрелочная функция или bind.
Забывают про ошибки вовсе: колбэк получает только результат, и сбой молча превращается в undefined, с которым дальше работает остальной код.