node相关知识点(上)(node指什么)

Node 里的模块是什么?

node 中,每个文件模块都是一个对象,它定义如下:

function Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  this.filename = null;
  this.loaded = false;
  this.children = [];
}

module.exports = Module;
var module = new Module(filename, parent);

require的模块加载机制

  1. 计算模块的绝对路径
  2. 如果缓存中有该模块,则从缓存中取出该模块
  3. 按优先级依次寻找并编译执行模块,将模块推入缓存(require.cache)中
  4. 输出模块的exports 属性

Node中内存泄漏问题和解决方案

内存泄漏原因

  • 全局变量:全局变量挂载在root对象上,不会被清除掉
  • 闭包:如果闭包未释放,就会导致内存泄漏
  • 事件监听: 对同一个事件重复监听,忘记移除(removeListener),将造成内存泄漏

解决方案

  • 最容易出现也是最难排查的就是事件监听造成的内存泄漏,所以事件监听这块需要格外注意小心使用。
  • 如果出现了内存泄漏问题,需要检测内存使用情况,对内存泄漏的位置进行定位,然后对对应的内存泄漏代码进行修复
  • 使用浏览器的快照功能来测试快速定位问题

两个模块相互引用会发生什么问题?

假设 A 和 B 模块相互引用,此时运行 A 模块

  • A 模块将会被缓存,但是此时缓存的是一个未执行完毕的 A 模块
  • A 模块引入 B 模块将会被完整地加载并且正常的使用
  • B 模块中调用 A 模块将会是默认的空对象(module.exports的默认值),A 模块不具有任何功能

如何实现热更新

node 中有一个Api 是 require.cache,如果这个对象中的引用被清除后,下次再调用就会重新加载,这个机制可以用来热加载更新的模块

function clearCache(modulePath) {
    const path = require.resolve(modulePath)
    if (require.cache[path]) {
        require.cache[path] = null
    }
}

然后使用 fs.watchFile 监听文件的更改,文件更改后调用 clearCache 传入对应的模块名

使用 pm2 reload 也可以实现暴力更新,它会保证在新的实例重启成功后才会把旧的进程杀死,可以保证服务一直能够响应

Node 适合处理 I/O 密集型任务

  • node 在处理 I/O 密集型任务的时候可以异步调用,利用事件循环的处理能力,资源占用极少,事件循环可以避开多线程调用,在调用方面是单线程,内部处理其实是多线程
  • javascript 是单线程的原因,node 不合适处理 CPU 密集型的任务, CPU 密集型的任务会导致CPU 时间片不能释放,使得后续 I/O 无法发起,从而会造成堵塞,这时候可以使用多线程来处理,但是js不支持多线程

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注