第 1 卷
深入解析 Node.js:事件循环与非阻塞 I/O
一、什么是Node.js?它是如何工作的?
- 什么是Node.js
你可以将Node.js理解为一个基于Chrome V8 JavaScript引擎构建的服务器端运行环境,它并非编程语言(仍使用JavaScript),也非框架,核心作用是让JavaScript脱离浏览器环境,能够在服务器端执
行文件读写、网络请求、数据库操作等后端开发任务。Node.js具有轻量、高效的特性,尤其适用于高并发的I/O密集型应用(如API接口、实时聊天、数据流处理等)。
- Node.js的工作原理
- 核心依赖:基于Chrome V8引擎(高性能JavaScript解释器,将JS代码编译为机器码执行,保证运
行效率),同时封装了libuv库(跨平台异步I/O库,提供事件循环、异步网络/文件操作等核心能力)。
- 单线程+事件驱动:Node.js主线程是单线程的,不会为每个请求创建新线程,而是通过事件驱动模
型处理并发请求⸺所有异步操作(如文件读取、网络请求)都会被委托给底层线程池(由libuv管理),主线程仅负责监听事件完成后的回调函数,避免了线程切换的开销。
- 执行流程:JS代码由V8引擎解析执行,遇到异步I/O操作时,Node.js将其移交libuv线程池处理,
主线程继续执行后续同步代码;当异步操作完成后,libuv会将对应的回调函数放入事件队列,等待事件循环取出并交由V8引擎执行。
二、Node.js中的全局对象有哪些?举例说明它们的用途
Node.js的全局对象无需通过 require() 导入,可在所有模块中直接访问,核心全局对象及用途如下:
1.global:Node.js的顶层全局对象(类似浏览器中的 window),所有全局变量(除了模块内的局部变量)都是 global 的属性。
- 用途:定义全局可访问的变量或方法。
◦ 示例:
Code block
1// 在任意模块中定义全局变量 2global.userName = "张三";
3// 在其他模块中可直接访问 4console.log(userName); // 输出:张三
- 用途:开发调试、日志记录。
◦ 示例:
Code block
1console.log("普通日志信息"); // 普通输出 2console.error("错误信息提示"); // 错误输出(通常显示为红色)
3console.table([{name: "张三"}, {name: "李四"}]); // 以表格形式输出数据
3.process:提供当前Node.js进程的信息和控制能力,是与操作系统交互的核心对象。
- 用途:获取进程参数、环境变量、退出进程、监听进程事件等。
◦ 示例:
Code block
| 1 | console.log(process.pid);//输出当前进程ID |
|---|---|
| 2 | console.log(process.env.NODE_ENV);//输出环境变量(如开发环境/生产环境) |
| 3 | process.exit(0);//正常退出进程(参数0表示正常退出,非0表示异常退出) |
| 4. Buffer:用于处理二进制数据(Node.js原生不支持直接操作二进制数据,Buffer是核心解 |
决方案)。
- 用途:文件读写、网络数据传输、加密解密等场景中的二进制数据处理。
◦ 示例:
Code block
1// 创建一个Buffer实例
| 2 | const buf = Buffer.from("Hello Node.js", "utf8"); |
|---|---|
| 3 | console.log(buf.toString("utf8"));//转换为字符串输出:Hello Node.js |
| 4 | console.log(buf.length);//输出Buffer的字节长度 |
| 5. setTimeout/setInterval/setImmediate:定时器相关全局方法,用于延迟或周期性 |
执行函数。
- 用途:延迟执行任务、定时轮询、立即执行异步任务等。
◦ 示例:
6setImmediate(() => console.log("立即异步执行"));
三、Node.js的事件循环机制,它如何处理异步操作?
- 事件循环(Event Loop)的核心定义
事件循环是Node.js实现非阻塞异步编程的核心机制,它是一个无限循环的流程,负责监听事件队列、取出异步操作完成后的回调函数,并将其交由V8引擎主线程执行,从而让单线程的Node.js能够处理大
量并发异步请求。
- 事件循环的阶段划分(从内到外,按执行优先级排序)
Node.js的事件循环分为6个阶段,每个阶段都会处理对应的回调队列,只有当前阶段的队列处理完毕(或达到最大执行数),才会进入下一个阶段:
- timers(定时器阶段):处理 setTimeout 和 setInterval 的回调函数(延迟时间到期后的
回调)。
- pending callbacks(待定回调阶段):处理少数系统级回调(如TCP连接错误的回调)。
- idle, prepare(空闲/准备阶段):内部使用,开发者无需关注。
- poll(轮询阶段):核心阶段,负责监听I/O事件(文件I/O、网络I/O等),并处理对应的回调;若
没有待处理的回调,会在此阶段阻塞等待新的I/O事件。
- check(检查阶段):处理 setImmediate 方法注册的回调函数。
- close callbacks(关闭回调阶段):处理关闭事件的回调(如 socket.on('close',
callback))。
- 事件循环处理异步操作的流程
- 同步代码优先执行:Node.js启动后,先执行当前模块的同步代码,遇到异步操作(如
setTimeout、文件读取),不会阻塞主线程,而是将异步任务委托给底层libuv线程池(或系统内核)处理,同时将回调函数注册到对应的事件队列中。
- 进入事件循环:同步代码执行完毕后,主线程进入事件循环,按照上述6个阶段的优先级,依次处
理每个阶段的回调队列。
- 回调执行与循环往复:每个阶段的回调队列处理完毕后,进入下一个阶段;当所有6个阶段处理完
毕后,事件循环会再次从头开始(timers阶段),形成无限循环,直到没有待处理的回调和进程退出。
- 微任务队列的优先级:在每个事件循环阶段切换之前,会先处理所有微任务队列中的回调
全站分卷索引 · 12 卷
- 1第 1 卷
- 2第 2 卷
- 四、Node.js中的非阻塞I/O(Non-blocking I/O)模型
- • 阻塞I/O:主线程发起I/O操作后,暂停执行所有代码,直到I/O操作完成(如传统的PHP文件读
- • 非阻塞I/O:主线程发起I/O操作后,立即返回一个状态(未完成),并继续执行后续代码;I/O操作
- • exports:是 module.exports 的一个引用(快捷方式),默认是一个空对象 {},只能通
- • module.exports:是模块的真正导出对象,Node.js最终导出的是 module.exports 的
- ◦ 若为相对路径( ./、 ../)或绝对路径,直接按路径查找对应
- ◦ 若为第三方模块(如 express),会在当前目录的 node_modules 文件夹中查找,若找不
- 3第 3 卷
- 4第 4 卷
- 5第 5 卷
- 6第 6 卷
- 7第 7 卷
- 8第 8 卷
- 9第 9 卷
- 10第 10 卷
- 11第 11 卷
- 12第 12 卷