Циклический require в CommonJS
Вопрос
a.js делает const b = require("./b"), а b.js в начале делает const a = require("./a") и в своей функции вызывает a.helper(). a.js экспортирует module.exports = { helper } в конце файла. Что произойдёт при запуске node a.js и вызове функции из b во время загрузки?
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Варианты ответа
- Node обнаружит цикл и бросит ошибку ERR_REQUIRE_CYCLE при загрузке
- Node загрузит
aповторно с начала, и всё сработает - Будет бесконечная рекурсия загрузки и переполнение стека
bполучит пустойmodule.exportsизa,helperundefinedправильный ответ
Разбор
CommonJS кеширует модуль в require.cache до выполнения его кода. Когда b требует a, который ещё выполняется, он получает текущий module.exports модуля a: пустой объект, потому что присваивание стоит в конце файла. Ошибки нет, рекурсии нет, повторной загрузки нет, просто TypeError: a.helper is not a function в момент вызова.
Лечение: разорвать цикл (вынести общее в третий модуль), обращаться к зависимости лениво внутри функций, а не на верхнем уровне, или не переприсваивать module.exports, а дописывать свойства в exports. В ESM циклы обрабатываются через живые привязки, но там своя ловушка с обращением до инициализации (TDZ).
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.