Node.js如何检测JSON文件变更并读取更新后的内容?
require() 加载JSON文件时自带全局缓存逻辑:第一次成功加载文件后,后续所有指向同一路径的require()调用都会直接返回内存中缓存的首次加载结果,不会重新访问磁盘读取文件。之前不管是事件回调里重复require还是无限循环require都拿不到新值,就是这个缓存机制导致的。
方案一:清除require缓存后重新加载(仅适合快速验证,不推荐生产用)
每次调用require前,先把对应文件的缓存从require.cache对象中删除即可,注意缓存的键是文件的绝对路径,传相对路径会导致清缓存失败:const path = require('path') const jsonAbsPath = path.resolve(__dirname, './jsonfile.json') // 事件回调逻辑 delete require.cache[jsonAbsPath] const jsonData = require(jsonAbsPath) console.log(jsonData.variable)这个方案缺陷很明显:如果外部程序还没写完JSON文件时刚好触发读取,会读到半写入的损坏内容直接抛错;另外路径处理稍有问题就会清缓存失败,稳定性差。
方案二:用内置fs模块直接读取文件(适合按需读取的场景,稳定性高)
绕开require的缓存逻辑,每次需要取值时直接通过fs模块读取磁盘上的文件内容,手动解析JSON:const fs = require('fs/promises') const path = require('path') const jsonAbsPath = path.resolve(__dirname, './jsonfile.json') async function getJsonVariable() { // 直接读取磁盘上的最新文件内容 const fileContent = await fs.readFile(jsonAbsPath, 'utf-8') const jsonData = JSON.parse(fileContent) return jsonData.variable } // 事件触发时调用即可 eventHandle(() => { getJsonVariable().then(val => console.log(val)) })如果怕读到半写入的损坏文件,可以加个简单的重试逻辑,JSON解析失败时等待50-100ms再重新读取即可。
方案三:监听文件变更自动更新内存值(适合需要实时感知变更的场景,性能最好)
用Node.js内置的fs.watch方法监听目标JSON文件的修改事件,文件发生变化时自动读取最新内容更新到内存变量中,业务逻辑直接读内存变量即可,不需要每次触发事件都访问磁盘:const fs = require('fs') const path = require('path') const jsonAbsPath = path.resolve(__dirname, './jsonfile.json') // 存储最新JSON值的内存变量 let latestJsonData = {} let reloadTimer = null // 统一的加载文件方法 function reloadJson() { try { const content = fs.readFileSync(jsonAbsPath, 'utf-8') latestJsonData = JSON.parse(content) } catch (err) { console.error('JSON文件加载失败,大概率是文件正在写入:', err.message) } } // 初始化时第一次加载 reloadJson() // 监听文件变化,加防抖避免重复触发,同时延迟100ms读取等文件写完 fs.watch(jsonAbsPath, () => { clearTimeout(reloadTimer) reloadTimer = setTimeout(reloadJson, 100) }) // 业务事件回调里直接读内存值即可 eventHandle(() => { console.log(latestJsonData.variable) })注意:不同操作系统下
fs.watch的触发逻辑有细微差异,极端场景可能出现漏触发的问题,生产环境可以加个间隔几秒的轮询兜底,定期校验文件内容,避免监听失效导致长期读到旧值。
内容的提问来源于stack exchange,提问作者william

