美文网首页
NodeJs的事件循环、垃圾回收、调试

NodeJs的事件循环、垃圾回收、调试

作者: 樗云 | 来源:发表于2025-06-17 21:01 被阅读0次

Nodejs事件循环

与浏览器的事件循环不同,Node.js 的事件循环构建在 libuv 库之上,专为 I/O 密集型操作优化。

node启动后,先执行完所有的同步代码,再执行队列中所有的process.nextTick 和微任务,最后进入事件循环。

  1. Timers:执行 setTimeout() 和 setInterval() 的回调。
    注意,其中每执行完一个立刻执行队列中所有的process.nextTick 和微任务,再执行下一个Timer回调。
  2. IO callbacks:处理一些系统级的 I/O 回调,如TCP错误。
  3. Idle, Prepare:Node内部使用,不常见。
  4. Poll:检索新的 I/O 事件,执行与 I/O 相关的回调。(新请求、异步文件读取等)
    在此期间如果没有其他阶段的任务需要执行,那么将一直处于 poll 阶段,以保证对IO事件的尽快响应。
  5. Check:执行 setImmediate() 回调。
  6. Close Callbacks:处理关闭的回调,如 socket.on('close', ...)

在每两个阶段之间都会依次执行process.nextTick 和 微任务(Promise回调、await回调)队列。
注意,同一阶段中,process.nextTick 总是优先于其他微任务执行。

定时器

NodeJS中的定时器是由timers模块实现的,该模块是全局的,因此无需被require,但其原理与浏览器端不同,是基于Node.js 事件循环构建。

  • setTimeoutsetIntervalsetImmediate定时器函数返回值在浏览器端是一个定时器id数字,但在Node端是当前定时器的实例对象,同时其中函数的this指向也指向该定时器实例对象。
  • 定时器函数实例额外具有unref()ref()方法。
const timer = setTimeout(function(){console.log(this)}, 100);//Timeout
timer.unref(); // 事件循环在只有这个定时器时退出
timer.ref();   // 恢复默认行为
  • 注意:Node中setTimeout有最小间隔1ms,因此根据主代码中同步任务执行情况可能导致setTimeoutsetImmediate先执行(例如耗时不到1ms,直接进入了Timers阶段)。
    因此通常将其放到Timers之后的阶段中执行,即可保证setImmediate先触发。
const fs = require('fs');
const path = require('path');

// 在IO结束的callback执行 也就是 poll 阶段会执行该 fs.readFile callback
// IO回调中存在 setImmediate 那么EventLoop的下一个阶段一定会进入check阶段
// 进而一定会优先执行 setImmediate 的回调
fs.readFile(path.resolve(__dirname, 'package.json'), (err) => {
  if (err) {
    console.log(err, 'err');
  }

  setTimeout(() => {
    console.log('timer');
  });

  setImmediate(() => {
    console.log('immediate');
  });
});
  • setImmediate可用在当前I/O 操作完成后立即执行某任务,或用于拆分复杂任务,避免阻塞事件循环。
    比起setTimeout(fn,0)开销更小,比起process.nextTick不容易饿死IO(阻塞事件循环)。
function heavyComputation(data) {
  if (data.length === 0) return;
  // 处理一部分
  processChunk(data.splice(0, 100));
  // 延迟下一轮
  setImmediate(() => heavyComputation(data));
}


性能

内存

NodeJs的垃圾回收和浏览器端差不多,额外有一些指令:

  • node --expose-gc xxx.js
    允许在代码中手动调用global.gc()触发垃圾回收。
  • node --trace_gc xxx.js
    node --trace_gc_nvp xxx.js
    打印垃圾回收的情况
  • 生成内存快照
    可用于查看内存中的对象数量、大小,并进行定位。
const { writeHeapSnapshot } = require('node:v8');//此处"node:"是NodeJs12+的新增语法,用于防止引用的模块重名
v8.writeHeapSnapshot()
  • 调整新/旧堆空间大小:
node --max-semi-space-size=64 app.js
node --max-old-space-size=4096 app.js
  • 调整垃圾收集频率(ms)
node --gc-interval=100 app.js
  • process.memoryUsage
    查看当前进程内存使用情况
process.memoryUsage()
{
  rss: 35438592,
  heapTotal: 6799360,
  heapUsed: 4892976,
  external: 939130,
  arrayBuffers: 11170
}

CPU
  • 使用V8内置分析器

使用--prof启动

node --prof xxx.js

将得到的log文件转化成txt格式:

node --prof-process isolate-0xnnnnnnnnnnnn-v8.log > processed.txt
  • 使用火焰图

调试

  1. 使用--inspect指令进行调试
    通过node --inspect xxx.js指令启动NodeJs后,进入Chrome浏览器chrome://inspect页面,在Remote Target部分即可使用Chrome DevTools调试NodeJs应用,可以在其中打断点、使用Console、Network、Performance、Memory等。
  2. 在VSCode中进行调试

相关文章

  • Node事件循环和多进程

    nodejs事件循环与多进程 why 事件循环对于深入理解nodejs异步至关重要fs, net,http,eve...

  • go-runtime/debug

    程序包调试了包含程序在运行时进行调试功能,本节就针对api进行一一讲解 1.强制进行垃圾回收 2.设置垃圾回收的目...

  • JVM(六)垃圾回收机制及算法

    1. 垃圾回收概述 什么是垃圾回收?垃圾收集(Garbage Collection,也就是GC)需要完成的三件事件...

  • 2022年javascript面试题总结

    什么是 javascript 数据类型 判断数据类型的方法 事件循环机制 垃圾回收机制和内存泄漏 闭包 递归 原型...

  • JS 项目优化

    https://segmentfault.com/a/1190000000490324 优化循环 垃圾回收*1。 ...

  • iOS RunLoop由浅入深

    Event Loop Event Loop事件循环机制,如javascript的事件循环,以及依赖其的nodejs...

  • nodejs事件循环

    1. 只有一个主线程,node开始执行脚本时,会先进事件循环初始化(同步任务,发出异步请求,规划定时器生效时间,执...

  • nodeJS事件循环

    Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。 Node.js 的每一个 A...

  • Nodejs事件循环

    Nodejs是基于事件驱动的,实际上与dom操作的操作事件差不多,诸如onclick之流 Nodejs定义事件需要...

  • NodeJS 事件循环

网友评论

      本文标题:NodeJs的事件循环、垃圾回收、调试

      本文链接:https://www.haomeiwen.com/subject/phecgjtx.html