源本科技 | 码上会

Node.js 核心原理

2026/04/05
1
0

Node.js中事件循环的工作机制是什么

Node.js 是单线程运行,事件循环就是它处理异步回调的核心调度机制,用来保证代码不阻塞。 它分成 6 个固定阶段按顺序执行:timers、pending callbacks、idle/prepare、poll、check、close callbacks。 主线程先把所有同步代码跑完,再进入事件循环。每个阶段会执行对应队列里的回调,执行完再进入下一个阶段。像 setTimeout 这类延时任务放 timers 阶段,I/O 回调放 poll 阶段。每一轮循环会先清空微任务,再执行宏任务,不断循环处理事件,让单线程也能高效处理大量异步操作,不会卡死主线程。

Node.js的事件循环如何与操作系统交互

事件循环本身不直接做 I/O,而是靠底层库 libuv 跟操作系统打交道。 当 Node.js 发起文件、网络等 I/O 请求时,libuv 会把请求交给操作系统内核处理,主线程直接去做别的事,不等待结果。 操作系统内核有自己的异步通知机制:Linux 用 epoll、macOS 用 kqueue、Windows 用 IOCP。内核完成 I/O 后,会主动通知 libuv,libuv 再把对应的回调函数放进事件循环的对应阶段队列。等事件循环跑到该阶段,就会执行回调。简单说:Node.js 负责调度,系统负责干活,libuv 做中间衔接。

Node.js中的微任务和宏任务有什么区别

宏任务和微任务是 Node.js 异步任务的两种优先级,执行时机完全不同。 宏任务是事件循环各个阶段的任务,比如 setTimeout、setImmediate、I/O 回调、close 事件,每次循环只执行当前阶段的一批宏任务。 微任务优先级远高于宏任务,比如 process.nextTick、Promise.then,每次宏任务执行完,会先把微任务队列清空,再进入下一个宏任务阶段。 而且 nextTick 比 Promise 微任务更早执行。微任务会“插队”,滥用会阻塞事件循环;宏任务则按阶段有序执行,不会抢占。

Node.js的非阻塞I/O模型是如何工作的

Node.js 单线程能扛高并发,全靠非阻塞 I/O。 当代码发起文件读取、网络请求等 I/O 操作时,主线程不会原地等结果,而是把请求交给 libuv,立刻继续执行后面的同步代码。 libuv 会通过操作系统的异步接口处理 I/O,内核在后台跑,不占用 Node.js 主线程。等内核完成 I/O 后,通知 libuv,把回调丢进事件队列。 主线程只要在事件循环里取回调执行就行。部分密集型 I/O 会交给底层线程池,但主线程始终不阻塞,这就是非阻塞 I/O 的核心,特别适合高并发网络服务。

Node.js的事件驱动架构是什么

Node.js 是典型的事件驱动架构,核心逻辑就是:事件触发 → 执行回调。 所有操作都被抽象成“事件”:HTTP 请求进来是 request 事件、数据到达是 data 事件、连接关闭是 close 事件。 底层依靠 EventEmitter 类实现事件的监听、发射和回调绑定。 程序不会主动轮询查状态,而是被动等事件触发,再执行对应的处理函数。整个流程由事件循环统一调度,不阻塞主线程。这种架构让 Node.js 轻量、高效,是它能做高并发服务的底层基础。

Node.js中的事件驱动编程模型有什么特点和优势

事件驱动编程的特点很鲜明:单线程、非阻塞、基于事件触发回调、依赖 EventEmitter、无轮询。 优势非常突出:一是高并发能力强,单线程就能处理大量请求,没有多线程切换开销;二是资源占用低,轻量高效,适合网关、API 服务;三是代码逻辑清晰,异步流程用事件 / 回调组织,可读性高;四是扩展性好,方便做插件化、中间件。 唯一短板是不适合 CPU 密集型任务,容易阻塞事件循环。整体上,它比传统多线程模型更适合网络 I/O 密集场景。

Node.js中的V8引擎是如何优化JavaScript执行的

V8 是 Node.js 的 JS 执行引擎,靠一堆优化让 JS 跑的接近编译型语言。 首先用 JIT 即时编译,把 JS 直接转成机器码,不是慢慢解释执行。然后用隐藏类给对象固定结构,快速访问属性,避免动态查找。 还有内联缓存,缓存函数调用结果,减少重复计算。垃圾回收分代处理,新生代快速清理,老生代高效回收,降低卡顿。 热点代码会交给 TurboFan 优化编译器深度优化,复杂代码用 Ignition 解释器兜底,兼顾速度和兼容性,让 JS 执行效率大幅提升。

Node.js中Buffer对象的作用和特点

Buffer 是 Node.js 专门用来处理二进制数据的核心对象,弥补 JS 原生没有二进制类型的缺陷。 主要用来处理文件、网络传输的流、图片 / 视频、加解密等二进制数据。 特点:固定长度、分配在堆外内存,不受 V8 垃圾回收管控;以字节为单位存储,支持 utf8、base64、hex 等多种编码;可与字符串、数组互转;全局可用,不用手动引入;底层直接操作二进制,效率极高,是 Node.js 所有 I/O 操作的基础数据类型。

解释Node.js中的全局对象和全局变量的概念

Node.js 里的全局对象是顶层载体,旧版是 global,新版推荐 globalThis,所有全局成员都挂在它上面。 全局变量就是挂载在全局对象上、可以直接使用的属性 / 方法,不用引入、不用声明。 常见的有:process、console、Buffer、setTimeout、__dirname、__filename 等。 注意:Node.js 每个文件都是独立模块,顶层声明的 var/let/const 不是全局变量,只会在当前模块生效,只有手动挂到 global 上才是真正的全局变量。

Node.js中的非同步循环和同步循环有何区别

同步循环就是我们常用的 for、while、forEach,会阻塞主线程。 循环执行期间,事件循环完全暂停,不能处理任何异步回调,哪怕是简单的请求也会卡住。如果是大数据量、CPU 密集的循环,会直接让服务卡死无响应。 非同步循环是用 setTimeout、Promise、async/await 封装的循环,每一轮都会让出主线程,给事件循环执行其他回调的机会,不会阻塞。 核心区别:同步循环阻塞事件循环,非同步不阻塞。服务端开发尽量用非同步循环,保证服务可用。