← Назад к вопросам

Что будет при повторном написании require в CommonJS?

2.0 Middle🔥 112 комментариев
#Другое

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизм кеширования модулей в CommonJS

При повторном вызове require() для одного и того же модуля в CommonJS происходит возврат кешированного экземпляра модуля, а не его повторное выполнение. Это фундаментальное поведение системы модулей Node.js, обеспечивающее эффективность и предотвращающее побочные эффекты.

Как работает кеширование

Когда модуль загружается впервые, Node.js выполняет следующие шаги:

  1. Разрешение пути - определение абсолютного пути к файлу
  2. Загрузка и компиляция - чтение файла, оборачивание в функцию-оболочку
  3. Выполнение кода модуля
  4. Сохранение в кеше - результат помещается в объект require.cache

При последующих вызовах require() для того же пути система проверяет кеш и возвращает уже вычисленный результат.

Практическая демонстрация

Рассмотрим пример, наглядно показывающий механизм кеширования:

moduleA.js:

console.log('Модуль A загружается...');
let counter = 0;

module.exports = {
    increment: () => ++counter,
    getCount: () => counter
};

main.js:

const module1 = require('./moduleA');
const module2 = require('./moduleA');

console.log(module1 === module2); // true - один и тот же объект

module1.increment();
console.log(module2.getCount()); // 1 - состояние общее

// Проверка кеша
console.log(require.cache[require.resolve('./moduleA')]);

При выполнении node main.js будет выведено:

Модуль A загружается...
true
1
[Object: null prototype] { ... } // информация о кешированном модуле

Ключевые аспекты поведения

  1. Синглтон по умолчанию - модуль становится синглтоном в рамках процесса
  2. Кеширование по абсолютному пути - даже если использовать разные варианты пути к одному файлу, после разрешения они приведут к одному ключу в кеше
  3. Состояние сохраняется - любые изменения в модуле (переменные, объекты) видны всем потребителям

Объект require.cache

Кеш модулей доступен через require.cache - это объект, где ключами являются абсолютные пути к модулям. С ним можно работать программно:

// Удаление модуля из кеша
delete require.cache[require.resolve('./moduleA')];

// После удаления require() загрузит модуль заново
const freshModule = require('./moduleA'); // Будет выполнено повторно

Практические последствия и рекомендации

  • Глобальное состояние - изменения в модуле влияют на всю программу
  • Потенциальные утечки памяти - модули остаются в памяти пока работает процесс
  • Тестирование - для изолированного тестирования нужно очищать кеш между тестами
  • Горячая перезагрузка - в development-режиме можно реализовать перезагрузку модулей через очистку кеша

Сравнение с другими системами модулей

В отличие от CommonJS, ES-модули (использующие import) также кешируют загруженные модули, но с более строгой семантикой. В ES-модулях связывание происходит статически на этапе компиляции, а не выполнения.

Исключения и особенности

  1. Циклические зависимости - обрабатываются специальным образом, с частично загруженными модулями
  2. Модули ядра Node.js - кешируются на более низком уровне
  3. JSON-файлы - также кешируются после парсинга
  4. Нативные модули (.node файлы) - имеют отдельный механизм загрузки

Вывод

Повторный require() в CommonJS — это не загрузка файла с диска, а обращение к кешу. Это проектировочное решение обеспечивает предсказуемость, производительность и единое состояние модулей в приложении. Понимание этого механизма критически важно для разработки масштабируемых приложений на Node.js, особенно при работе с состоянием, тестированием и динамической загрузкой модулей.