
在 node.js repl 中多次使用 require() 加载同一脚本时,node 默认从缓存中返回模块,导致后续文件内容变更不会生效;需手动清除缓存或改用动态导入才能获取最新代码。
在 node.js repl 中多次使用 require() 加载同一脚本时,node 默认从缓存中返回模块,导致后续文件内容变更不会生效;需手动清除缓存或改用动态导入才能获取最新代码。
Node.js 的模块系统基于单次执行 + 缓存机制:首次调用 require('script.js') 会完整执行该文件(如初始化 global.testObject 并赋值),并将导出结果(module.exports)缓存到 require.cache 中;后续相同路径的 require() 调用将直接返回缓存值,不再重新执行脚本——这正是你修改 script.js 后 testObject.cont 未更新的根本原因。
✅ 正确解决方案
方案一:手动清除模块缓存(推荐用于 REPL 快速调试)
在 REPL 中执行以下代码,强制删除缓存并重新加载:
// 删除 script.js 的缓存条目(注意:需使用绝对路径)
delete require.cache[require.resolve('./script.js')];
// 重新加载(此时会重新执行脚本)
const reloaded = require('./script.js');⚠️ 注意事项:
- require.resolve('./script.js') 返回的是解析后的绝对路径,必须与缓存键完全匹配;
- 若脚本无显式 module.exports,require() 仍会返回 module.exports(默认为 {}),但全局变量(如 global.testObject)的修改已在首次执行时完成,因此清除缓存后重新 require 才能触发脚本重执行;
- 不要直接操作 require.cache = {},这会破坏其他已加载模块。
方案二:使用动态 import()(ESM 风格,Node ≥12+)
若脚本支持 ES 模块(或通过 .mjs 后缀/"type": "module" 声明),可利用动态导入绕过缓存:
// 在 REPL 中启用实验性 ESM 支持(需启动时加 --experimental-repl-await)
await import('./script.js?ts=' + Date.now()); // 添加时间戳参数防缓存(仅对 HTTP 有效,本地文件无效)但注意:本地文件的 import() 仍受 Node 模块解析缓存影响,真正可靠的刷新方式仍是清除 require.cache(方案一)。
方案三:重构脚本为可导出函数(最佳实践)
避免依赖全局变量,将逻辑封装为可重复调用的函数:
// script.js
module.exports = function() {
global.testObject = {};
testObject.cont = "This is an updated sample 2";
};在 REPL 中使用:
const loadScript = require('./script.js');
loadScript(); // 每次调用都执行最新逻辑? 总结
- require() 的缓存行为是设计使然,非 bug,目的是提升性能和保证模块单例;
- REPL 调试时,优先使用 delete require.cache[require.resolve(...)] 清除缓存;
- 长期开发建议采用函数导出模式,而非依赖全局状态或脚本自执行;
- 切勿在生产环境频繁清除缓存——应通过重启进程或热更新工具(如 nodemon)管理变更。


















