第二次引入不会重新执行模块代码,而是直接返回第一次加载后缓存的 module.exports 对象;node.js 通过 require.cache(以绝对路径为 key 的 module 实例映射)实现该行为,确保顶层语句仅执行一次、导出对象被共享。

CommonJS 的 require 加载模块时,**第二次引入不会重新执行模块代码,而是直接返回第一次加载后缓存的 module.exports 对象**。这不是“优化技巧”,而是 Node.js 模块系统强制保证的行为契约。
缓存机制的核心表现
每次 require('./utils') 调用,Node.js 都会先查 require.cache——一个以模块绝对路径为 key、Module 实例为 value 的对象。如果命中,就跳过文件读取、编译和执行,直接返回该模块的 exports。
- 模块顶层语句(如
console.log('init')、let count = 0)只运行一次 - 导出的对象(如
module.exports = { data: [] })是同一引用,所有require者共享 - 即使写法不同(
./utils和./utils.js),只要解析后指向同一文件,就共用一个缓存项
二次引入 ≠ 重新初始化
常见误解是“再次 require 就会重新跑一遍模块”。实际中:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 若模块导出一个对象:
module.exports = { counter: 0 },两次require得到的是同一个对象,修改其属性会影响所有使用者 - 若模块导出一个函数:
module.exports = () => {},两次require返回的是同一个函数引用,不是两个新函数 - 循环依赖场景下,缓存让模块能拿到对方“半初始化”的
exports,避免死锁
如何验证缓存是否生效
在 Node REPL 或脚本中快速确认:
- 模块内加
console.log('loaded'),首次require输出,后续不输出 - 执行
require('./a') === require('./a')返回true - 打印
Object.keys(require.cache)可见已加载模块的绝对路径列表
手动清除缓存的适用场景
正常业务中不需要也不建议清除缓存,但在开发调试或热重载时可临时使用:
- 调用
delete require.cache[require.resolve('./config.js')]清掉单个模块 - 注意:这仅清目标模块,其依赖仍留在缓存中;如需彻底重载,得递归清理子模块
- 生产环境禁用——可能引发状态不一致、内存泄漏或竞态问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










