Кешируется ли модуль при подключении с помощью require
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
require() кэширование в Node.js
Да, модули кэшируются! Это критично важная особенность Node.js, которая влияет на производительность и поведение приложения.
Как работает кэширование require
Первый импорт — исполнение кода:
// config.js
console.log('Файл config.js загружен');
module.exports = { apiUrl: 'http://localhost:3000' };
// app.js
const config = require('./config'); // Выведет: "Файл config.js загружен"
const config2 = require('./config'); // НЕ выведет ничего (использован кэш)
console.log(config === config2); // true — один и тот же объект!
Механизм кэширования:
Node.js хранит загруженные модули в объекте require.cache:
// Смотрим кэш
console.log(require.cache);
// {
// '/absolute/path/to/config.js': Module {
// exports: { apiUrl: 'http://localhost:3000' }
// },
// ...
// }
Практический пример
// counter.js
let count = 0;
module.exports = {
increment: () => ++count,
getCount: () => count
};
// main.js
const counter1 = require('./counter');
const counter2 = require('./counter');
counter1.increment();
counter1.increment();
console.log(counter1.getCount()); // 2
console.log(counter2.getCount()); // 2 — ОДИН И ТОТ ЖЕ объект
console.log(counter1 === counter2); // true
Это значит, что состояние разделяется между всеми частями приложения.
Очистка кэша require.cache
Иногда нужно очистить кэш (например в тестах):
// Удалить конкретный модуль
delete require.cache[require.resolve('./config')];
// Теперь следующий require выполнит файл заново
const config = require('./config'); // Выполнится снова!
Пример: сброс кэша для конфига:
// config.js
module.exports = {
debug: process.env.DEBUG === 'true',
apiUrl: process.env.API_URL
};
// test.js
describe('Config', () => {
beforeEach(() => {
// Очищаем кэш перед каждым тестом
delete require.cache[require.resolve('./config')];
});
it('uses DEBUG env variable', () => {
process.env.DEBUG = 'true';
const config = require('./config');
expect(config.debug).toBe(true);
});
});
Кэширование по абсолютному пути
Важно: кэширование работает по абсолютному пути!
// Если ты требуешь с разными путями — разные кэши
const mod1 = require('./module');
const mod2 = require('./module.js');
const mod3 = require('/absolute/path/module.js');
// На одних системах — один объект, на других разные!
// (зависит от решения path resolution)
Правильно:
// Всегда используй одинаковые пути
const config = require('./config'); // Одна версия в кэше
const config2 = require('./config'); // Используется кэш
Циклические зависимости
Кэширование помогает избежать бесконечных циклов:
// module-a.js
const b = require('./module-b');
module.exports = { name: 'A', b };
// module-b.js
const a = require('./module-a');
module.exports = { name: 'B', a };
// main.js
const a = require('./module-a');
// Работает благодаря кэшированию — избегаем бесконечного цикла
Как это работает:
- Загружаем module-a
- module-a требует module-b
- module-b требует module-a (уже в процессе загрузки)
- Node.js возвращает ЧАСТИЧНО загруженный module-a из кэша
- Оба модуля завершают загрузку
Кэширование и Performance
Плюсы кэширования:
// Быстрое потребление памяти — модуль загружается один раз
const users = require('./models/users');
const orders = require('./models/orders');
const payments = require('./models/payments');
// Все используют один instance базы данных
Минусы — общее состояние может быть проблемой:
// database.js
const connections = [];
module.exports = {
addConnection: (conn) => connections.push(conn),
getConnections: () => connections
};
// service1.js
const db = require('./database');
db.addConnection({ id: 1 });
// service2.js
const db = require('./database');
console.log(db.getConnections()); // Видит соединение из service1!
Это может быть как плюсом (разделение ресурсов), так и минусом (побочные эффекты).
CommonJS vs ES6 modules
CommonJS (require) — кэшируется:
const config = require('./config');
const config2 = require('./config');
console.log(config === config2); // true
ES6 import — тоже кэшируется (в Node.js 12+):
import config from './config.js';
import config2 from './config.js';
console.log(config === config2); // true
Отключение кэша (редко нужно)
// Создание нового instance каждый раз
function requireFresh(modulePath) {
delete require.cache[require.resolve(modulePath)];
return require(modulePath);
}
// Использование
const config1 = requireFresh('./config');
const config2 = requireFresh('./config');
console.log(config1 === config2); // false — разные объекты
Когда нужно отключение кэша:
- Тестирование с разными конфигами
- Динамическая перезагрузка модулей (редко)
- HMR (Hot Module Replacement) в dev tools
Практический пример: Singleton паттерн
Кэширование require идеально для Singleton:
// database.js
class Database {
constructor() {
if (Database.instance) {
return Database.instance;
}
this.pool = null; // Инициализация
Database.instance = this;
}
connect(url) {
this.pool = new Pool({ connectionString: url });
}
getPool() {
return this.pool;
}
}
module.exports = new Database();
// app.js
const db = require('./database');
const db2 = require('./database');
console.log(db === db2); // true — один instance
db.connect('postgres://...');
// db2 видит то же соединение
Изучение кэша
// Функция для отладки кэша
function showCache(pattern) {
Object.keys(require.cache)
.filter(key => key.includes(pattern))
.forEach(key => {
console.log(key);
});
}
showCache('config'); // Показывает все загруженные config модули
showCache('database'); // Показывает все database модули
Итого: ключевые моменты
- require() кэшируется автоматически по абсолютному пути модуля
- Второй и все последующие требования используют кэш — код модуля не выполняется снова
- Вернётся одного объект — require.cache содержит тот же экземпляр
- Состояние разделяется — все части кода видят одно и то же состояние модуля
- Очистка кэша:
delete require.cache[require.resolve('./module')] - Цикличеч зависимости работают благодаря кэшированию
- Кэширование помогает реализовать Singleton паттерн
Это одна из самых важных особенностей Node.js, которая влияет на архитектуру приложения.