关于require引入单个文件的问题

本文探讨了Node.js中require的缓存机制如何影响动态文件的加载,通过实例展示了require缓存导致的问题,并提供了解决方案,即使用fs模块直接读取文件内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

Node.js的模块化是基于CommonJS规范实现的,我们通常会使用module.exports来导出一个模块,用require来引入一个模块。其实在Node.js中,一个文件就是一个模块,更多时候我们使用require来引入一些NPM包。例如:

const _ = require('lodash')

// codes

但是有时候我们也需要引入一些文件,最常见的文件就是.json文件,例如:

const package = require('./package.json')

// codes

用这种方式引入单个文件在大多数情况下是可行的,但是如果引入的文件是一个可能会在程序启动后发生变化的文件就会有问题了。

require的缓存机制

当程序启动后,Node.js会在当前进程缓存所有用require引入过的内容,并保存在全局对象require.cache中。所以,如果使用require引入一个动态文件,在程序运行过程中就无法获取最新的文件内容了。

我们来看一个测试:

const fs = require('fs')

const test = () => {
  // 首次引用config.json
  const config1 = require('./config.json')
  console.log('first require config')
  console.log(config1)

  console.log('require cache:')
  console.log(require.cache)

  // 修改config.json
  const str = fs.readFileSync('./config.json', 'utf8')
  const obj = JSON.parse(str)
  obj.age = 20
  fs.writeFileSync('config.json', JSON.stringify(obj, null, 2))

  // 第二次引用config.json
  const config2 = require('./config.json')
  console.log('second require config')
  console.log(config2)
}

test()

config.json文件中的内容为:

{
  "name": "blackmatch",
  "age": 18
}

输出结果:

first require config
{ name: 'blackmatch', age: 18 }
require cache:
{ '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/test.js':
   Module {
     id: '.',
     exports: {},
     parent: null,
     filename: '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/test.js',
     loaded: false,
     children: [ [Object] ],
     paths:
      [ '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/node_modules',
        '/Users/blackmatch/Desktop/blackmatch/demos/node_modules',
        '/Users/blackmatch/Desktop/blackmatch/node_modules',
        '/Users/blackmatch/Desktop/node_modules',
        '/Users/blackmatch/node_modules',
        '/Users/node_modules',
        '/node_modules' ] },
  '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/config.json':
   Module {
     id: '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/config.json',
     exports: { name: 'blackmatch', age: 18 },
     parent:
      Module {
        id: '.',
        exports: {},
        parent: null,
        filename: '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/test.js',
        loaded: false,
        children: [Object],
        paths: [Object] },
     filename: '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/config.json',
     loaded: true,
     children: [],
     paths:
      [ '/Users/blackmatch/Desktop/blackmatch/demos/require-cache-demo/node_modules',
        '/Users/blackmatch/Desktop/blackmatch/demos/node_modules',
        '/Users/blackmatch/Desktop/blackmatch/node_modules',
        '/Users/blackmatch/Desktop/node_modules',
        '/Users/blackmatch/node_modules',
        '/Users/node_modules',
        '/node_modules' ] } }
second require config
{ name: 'blackmatch', age: 18 }

从输出结果可以看出:

  • config.json文件被缓存到了require.cache全局对象中了。
  • 在config.json文件被修改后,第二次使用require引入文件无法获取该文件最新的内容。

这就是require的缓存机制。

使用读取文件的方式引入动态文件

同样基于上面的例子,我们使用读取文件的方式引入config.json,代码如下:

const fs = require('fs')

const test2 = () => {
  // 首次引用config.json
  const str1 = fs.readFileSync('./config.json', 'utf8')
  const config1 = JSON.parse(str1)
  console.log('first require config')
  console.log(config1)

  // 修改config.json
  const str = fs.readFileSync('./config.json', 'utf8')
  const obj = JSON.parse(str)
  obj.age = 20
  fs.writeFileSync('config.json', JSON.stringify(obj, null, 2))

  // 第二次引用config.json
  const str2 = fs.readFileSync('./config.json', 'utf8')
  const config2 = JSON.parse(str2)
  console.log('second require config')
  console.log(config2)
}

test2()

输出结果:

first require config
{ name: 'blackmatch', age: 18 }
second require config
{ name: 'blackmatch', age: 20 }

这次就能获取config.json最新的内容了。

总结

  • 引入一个动态文件的场景比较少,但养成使用读取文件的方式来引入单个文件是个好习惯。
  • 由于require的缓存机制,在需要热更新的场景可能需要另辟蹊径,必要时重启进程。

 

转载自:https://cnodejs.org/topic/5cffba0b1fe902120f31dd35

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值