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

前言

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
yog-log 是 Node Log 统计方案,是yog框架的log统计模块,支持中间件或者单独使用等方式,兼容ODP日志格式与配置。关于ODP的日志方案调研可查看此文档. 统计日志类型包括: server日志 access_log: web访问日志,按小时分日志 error_log: web错误日志,按小时分日志 访问日志统计方式为请求返还才触发。 应用日志 每个app有各自独立的日志,日志名为app的名称,例如demo.log和demo.log.wf。 可配置每个app是否使用独立的子目录存放自身日志,例如demo/demo.log。 可配置每个app是否按小时切分日志。 可配置每个app的日志级别。 对于不属于任何app的node.js程序,日志名为unknown.log。 快速开始 1 在yog的config.json中添加此配置   "yogLogger": {             "enabled": true,             "priority": 50,             "module": {                 "name": "yog-log",                 "arguments": [                     {                         "level" : 16, //线上一般填4,参见配置项说明                         "app": "app_name", //app名称,产品线或项目名称等                         "log_path": "path:./data/log"//日志存放地址                     }              ]       }  } 填写此配置之后yog-log就开始统计访问日志。 2 调用接口统计应用日志 router层统计日志 router层推荐使用emit方式触发log事件,避免在每个文件中都require yog-log try{     //do something }catch(e){     res.emit('log',{'stack':e,'errno':120,'msg' :'error happened!'}, 'warning'); //推荐方式     //or res.emit('log',{'stack':e});//日志等级不写默认为notice     //or res.emit('log','error!');//只写字符串不会解析错误堆栈 } model等没有res的地方 使用getLogger方法获取到日志模块实例,然后调用接口统计日志。 var YLogger = require('yog-log'); var logger = YLogger.getLogger();  //默认通过domain获取,单独使用请传递 configlogger.log('warning','msg'); //or logger.warning('msg'); 日志初始化配置项 配置项均有默认值,理论上不需要配置也能工作。推荐设置配置有:level、app、log_path 三项。 配置项 默认值 说明 app unknown app名称,推荐填写 format 见下 默认应用日志格式 format_wf 见下 默认的应用日志warning及fatal日志格式 level 16 log日志级别,高于此级别的日志不会输出 auto_rotate 1 是否自动切分 use_sub_dir 1 日志是否在二级目录打印,目录名为 APP_NAME log_path 插件安装地址/log 日志存放目录,注意需要设置 data_path 插件安装地址/data 格式数据存放的目录,可不用设置 is_omp 0 是否开启omp日志,如果不接入omp,建议置为2 debug 0 是否开启omp日志,如果不接入omp,建议置为2 默认`format`: %L: %t [%f:%N] errno[%E] logId[%l] uri[%U] user[%u] refer[%{referer}i] cookie[%{cookie}i] %S %M 默认的`format_wf `: %L: %{%m-%d %H:%M:%S}t %{app}x * %{pid}x [logid=%l filename=%f lineno=%N errno=%{err_no}x %{encoded_str_array}x errmsg=%{u_err_msg}x] 应用日志等级 日志等级 数据编号 统计说明 FATAL 1 打印FATAL WARNING 2 打印FATAL和WARNING NOTICE 4 打印FATAL、WARNING、NOTICE(线上程序正常运行时的配置) TRACE 8 打印FATAL、WARNING、NOTICE、TRACE(线上程序异常时使用该配置) DEBUG 16 打印FATAL、WARNING、NOTICE、TRACE、DEBUG(测试环境配 response.emit(name,obj,level) 在router层使用emit方式可以避免每个文件引入logger和获取实例。参数说明: name :日志事件名称,固定为'log' obj: string或者object格式。如果是string,认为是错误消息。如果是object,请认为是详细信息。正确格式为{'stack':e,'msg':'msg','errno':'010'},分别代表错误堆栈、错误消息、错误码。错误消息如果不填将使用错误堆栈的消息。 level : 日志等级字符串,见上。不区分大小写,不写默认为notice 如下所示: res.emit('log',{'stack':e,'errno':120,'msg' :'error happened!'},'warning'); getLogger(config) 当框架接收请求时,yog-log会新建一个实例,并保存到domain中,确保单次请求流程中调用的getLogger获取到的是同一个实例。 如果单独使用log不经过请求, getLogger会新建一个实例,此时应当传递config配置参数。 log(level,obj) 提供统一的log方法打印日志。参数说明同response.emit。另外针对各个应用日志等级提供了相对应的方法。 请确保使用快捷方法时名称准确,否则程序将报错。 fatal   :  logger.fata(obj) warning : logger.warning(obj) notice : logger.notice(obj) trace : logger.trace(obj) debug : logger.debug(obj) 注意 : logger为通过getLogger获取到的日志模块实例 。 自定义错误消息 如果想在日志中填写自定义的日志字段用于追查错误,请在obj中加入custom对象,然后按照键值对应放在custom中。如下所示:  //router层  res.emit('log',{    'stack':e, //错误堆栈    'errno':120,  //错误码    'msg' :'error happened!',  //错误消息    'custom':{'key1' :'value1','key2':'value2'} //自定义消息  });   //其他地方  logger.log('warning', {    'stack':e, //错误堆栈    'errno':120,  //错误码    'msg' :'error happened!',  //错误消息    'custom':{'key1' :'value1','key2':'value2'} //自定义消息  }); 注意custom字段默认只会在warning和fatal日志中展现 生成的错误日志将会类似于下面的格式。其中可以看到custom字段已自动添加到日志中: WARNING: 07-03 16:44:55 yd * - [logid=868855481 filename=D:\fis\test\models\doc.js lineno=25 errno=120 key1=value1 key2=value2 errmsg=error happened!] Debug支持 处于debug模式下Log将在控制台输出错误日志,并根据错误日志类型显示不同的颜色,方便开发人员调试(debug模式下依旧会写日志到文件)。有两种方法开启debug模式: 开发时 :yog的config.json的yogLogger arguments添加参数debug : 1 即开启debug模式 线上 : 无论在线上还是线下都可以在url中添加query参数_node_debug=1 开启debug模式 日志格式配置 yog-log兼容ODP支持灵活的日志格式配置,以满足不同系统对日志的格式要求。如接入OMP时warning日志格式配置: %L: %{%m-%d %H:%M:%S}t %{app}x * %{pid}x [logid=%l filename=%f lineno=%N errno=%{err_no}x %{encoded_str_array}x errmsg=%{u_err_msg}x] 除非特殊情况,不建议随意修改日志格式配置。 格式配置方法如下: 字段 描述 %% 百分比字符串 %h name or address of remote-host %t 时间戳,支持自定义格式如%{%d/%b/%Y:%H:%M:%S %Z}t %i HTTP-header字段 %a 客户端IP %A server address %C 单个或全部cookie %D 请求消耗时间/ms %f 物理文件名称 %H 请求协议 %m 请求方法 %p 服务端端口 %q 请求query %U 请求URL %v HOSTNAME %V HTTP_HOST %L 当前日志等级 %N 错误发生行数 %E 错误码 %l LogID %M 错误消息 %x 内置的自定义数据,有pid、cookie、encoded_str_array等 测试说明 单元测试说明详见此文档 标签:yoglog
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值