第 2 卷
1// 同步代码,优先执行 2console.log("同步代码1");
3 4// 微任务:process.nextTick
5process.nextTick(() => console.log("process.nextTick 微任务"));
6 7// 异步任务:setTimeout(timers阶段)
8setTimeout(() => console.log("setTimeout 回调"), 0);
9 10// 微任务:Promise
11Promise.resolve().then(() => console.log("Promise 微任务"));
12 13// 异步任务:setImmediate(check阶段)
14setImmediate(() => console.log("setImmediate 回调"));
15 16// 同步代码,其次执行
17console.log("同步代码2");
18 19// 输出顺序:
20// 同步代码1 21// 同步代码2
22// process.nextTick 微任务 23// Promise 微任务
24// setTimeout 回调 25// setImmediate 回调
四、Node.js中的非阻塞I/O(Non-blocking I/O)模型
- 非阻塞I/O的核心定义
非阻塞I/O是Node.js的核心特性之一,指当Node.js发起I/O操作(文件读取、网络请求、数据库操作等)时,主线程无需阻塞等待I/O操作完成,而是可以继续执行后续的同步代码,当I/O操作完成后,通
过事件循环触发对应的回调函数进行处理。
- 非阻塞I/O与阻塞I/O的对比
• 阻塞I/O:主线程发起I/O操作后,暂停执行所有代码,直到I/O操作完成(如传统的PHP文件读
取),此时线程处于闲置状态,无法处理其他请求,并发性能低下。
• 非阻塞I/O:主线程发起I/O操作后,立即返回一个状态(未完成),并继续执行后续代码;I/O操作
通过 UV_THREADPOOL_SIZE 配置),将I/O操作委托给线程池处理,避免阻塞主线程。
- 事件驱动模型:非阻塞I/O的核心支撑,I/O操作完成后会触发对应的事件
(如 'data'、 'end'、 'close'),回调函数被放入事件队列,等待事件循环取出执行。
- 单线程主线程:主线程仅负责执行同步代码和回调函数,不参与具体的I/O操作,从而保证了非阻
塞的特性,同时避免了线程切换的开销。
示例(非阻塞文件读取):
Code block
1const fs = require('fs');
2
| 3 | //非阻塞I/O:fs.readFile(异步读取文件) |
|---|---|
| 4 | fs.readFile('test.txt', 'utf8', (err, data) => { |
| 5 | if (err) throw err; |
| 6 | console.log("文件读取完成:", data); |
| 7 | }); |
8 9// 主线程不阻塞,继续执行此代码
10console.log("发起文件读取后,立即执行此同步代码");
五、如何在Node.js中实现模块化?require和exports是如何工作的?
Node.js采用CommonJS模块化规范(浏览器端常用ES6模块化,Node.js也支持ES6模块,需配置 "type": "module"),核心用于解决代码复用、作用域隔离、依赖管理等问题。
- Node.js模块化的实现方式
Node.js中每个文件就是一个独立的模块,拥有独立的模块作用域(模块内的变量、方法默认仅在模块内部可访问,不会污染全局作用域),模块化的核心是「导出模块内容」和「导入模块内容」。
- exports / module.exports:模块导出
用于将模块内的变量、方法、对象暴露出去,供其他模块导入使用,两者本质上是同一个引用(初期),但存在细微区别:
• exports:是 module.exports 的一个引用(快捷方式),默认是一个空对象 {},只能通
过添加属性/方法的方式导出内容,不能直接赋值(直接赋值会断开与 module.exports 的引用关联)。
示例:
4// 导出方法 5exports.sayHello = function() {
6console.log("Hello CommonJS");
7};
• module.exports:是模块的真正导出对象,Node.js最终导出的是 module.exports 的
值,而非 exports。它既可以添加属性/方法,也可以直接赋值(如导出一个函数、类、非对象类型)。
示例:
Code block
1// 模块A:a.js 2// 方式1:添加属性(与exports效果一致)
3module.exports.age = 10;
| 4 | //方式2:直接赋值(导出一个函数,此时exports失效) |
|---|---|
| 5 | module.exports = function() { |
| 6 | return "直接导出一个函数"; |
| 7 | }; |
注意:若同时使用 exports 添加属性和 module.exports 直接赋值,最终导出结果以 module.exports 为准(因为 module.exports 的赋值会覆盖原有引用)。
- require():模块导入
用于导入其他模块导出的内容,返回值是目标模块的 module.exports 对象,其工作流程如下:
- 模块查找机制: require() 接收模块路径(相对路径、绝对路径、核心模块名、第三方模块
名),按以下优先级查找:
- 优先查找核心模块(如 fs、 path、 http,Node.js内置,无需安装);
◦ 若为相对路径( ./、 ../)或绝对路径,直接按路径查找对应
的 .js、 .json、 .node 文件(可省略后缀,Node.js会自动补全);
◦ 若为第三方模块(如 express),会在当前目录的 node_modules 文件夹中查找,若找不
到则向上级目录的 node_modules 递归查找,直到根目录;
- 模块缓存机制:首次导入某个模块时,Node.js会执行该模块的代码,并将模块的
module.exports 对象缓存到 require.cache 中;后续再次导入该模块时,不会重新执行模
全站分卷索引 · 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 卷