Node.js 内置模块
简介
之前说过,Node.js 中重要的两句话是
- Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
- Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
上面两句话,可以使用下面的图片来具体认识。
简单来说这幅图
最左边是指 application 的 javascript 代码运行在基于 Chrome V8 引擎的 javascript 运行环境
在这个环境中连接最右边的 非阻塞式I/O 模型的方式就是通过 中间 Node.js 内置计算机系统操作API(OS Operation) 来连接非阻塞式I/O 模型,在该模型中涉及到的运行方式也就是事件驱动的方式。
补充:上面整个流程的代码或数据流向,也就是从我们 JS 代码数据,交由 Chrpme V8 代码模块转换为 C++ 代码数据,C++ 拼接转换后的命令去操作计算机系统,获得操作后运行的数据或结果,再将结果交由 Chrome V8 代码模块转换为我们需要的 JS 代码数据形式,也就达到了我们通过 JS 代码操作计算机系统的行为。
Node.js bindings
下面介绍一下 Node.js bindings 部分,也就是 Node.js 内置API模块,该模块可以说是连接我们 JS 和 计算机底层的关键桥梁。
Node.js 内置API可以查看 Node.js 官方文档,需要注意的是,要关注自己的 Node.js 版本信息,查看对应版本的 API 功能。
比如 Node.js v14.21.2 版本对应的官方文档地址:https://nodejs.org/docs/latest-v14.x/api/
下面拿 event API下的事件通信类 EventEmitter 举例:
封装一个简单的 EventEmitter
子类,并在子类中使用观察者模式(抛事件的模式),来控制计算机系统发射一个随机数信息,之后通过EventEmitter
子类创建的实例,调用实例下监听器 addListener 方法,接受计算机发出的随机数信息。
lib.js 文件,封装 EventEmitter 子类模块文件,并在该文件中进行实例化,导出实例。
// 引入事件通信类
const EventEmitter = require('events').EventEmitter
// 创建事件通信的子类
class RandomNums extends EventEmitter {
constructor() {
super()
setInterval(() => {
// 通过事件通信的 emit Api 来发射事件 newlesson
this.emit('randomNums', { randomNums: Math.random() * 100 })
}, 3000)
}
}
// 实例化创建的子类
const randomNums = new RandomNums
// 导出模块
module.exports = randomNums
index.js 引入事件通信实例,添加监听器,获取发射事件信息。
// 引入模块
const randomNums = require('./lib')
// 为事件通信实例创建监听器,这样才可以获取 emit 发射的事件
// 补充:
// >>> 这种事件通信操作底层来抛出事件的能力,也就是观察者模式(抛事件模式)
// >>> 解决两个对象之间通信的问题的方法:观察者模式(抛事件模式) 和 调用相关函数
// >>> 观察者模式(抛事件模式) 使用情况在于 只需要抛出事件,不管谁去监听
// >>> 调用相关函数 使用情况在于 不清楚有没有通知者的存在,只管去监听就可以
randomNums.addListener('randomNums', (result) => {
// do someting ...
console.log('>>> result ', result)
})
其他 Node.js 内置 API 也可以自己去按照文档写对应的 demo,这样更容易理解内置 API 的实用性和重要性。
如果还需要细致理解底层代码,可以查看 Node.js 源码,按照 node.js API 方法到中间 Chrome V8 引擎转换模块到 C++ 操作模块这样的顺序去查看。
Node.js 寻找源码,直接在 Node.js 官网打开对应版本的文档,在文档的左侧目录下拉到最后面,选择 Code repository and issue tracker 的选项即可跳转对应的源码仓库。
这里我们以 Node.js v14.21.2 这个版本为例,简单介绍一下源码仓库对应我们需要查看的目录位置。
最外层的目录,有很多文件。
node.js 内置API功能文件路径 ./lib/ ,之前旧版本路径在 ./lib/internal/ 下面,需要细心查找。
在该路径下面我可以找到常用的 Node.js 内置功能 os, path, http 等。
这里我们简单看一个 os.js 模块里面核心代码。
该模块代码中通过 internalBinding(‘os’) 方法去调用 Chrome V8 模块里面封装的方法,之后就是在 os.js 文件中对这些方法进行封装,V8 模块会在这些方法中回调用我们需要的底层计算机传递的信息。
internalBinding(‘os’) 所引入 Chrome V8 模块里面封装的方法,这些方法是通过 C++ 编写,目录在 ./src/ 下面, 比如我们这引入了 os 模块,对应的就是 ./src/node_os.cc 文件。
在该文件中我们可以看到,通过 Chrome V8 引擎内置 C++ 方法,来实现底层 C++ 数据到 JS 数据的转换。
node_os.cc 文件中定义了 Chrome V8 方法
这些方法在 Chrome V8 上下文中处理了 c++ 数据到 JS 数据的转换
比如我们的 GetCpuInfo 就是 C++ 实现获取 CPU 数据,并将该数据转化为 JS 环境可用的数据方法。
下面图片中圈中的第一行代码就是 C++ 底层获取 CPU 信息的方法,或取到数据后,通过第二行代码,调用 Chrome V8 的内置方法来实现 C++ 数据到 JS 数据的转换。
以上简单介绍了源码以及拿 os 模块举例源码的阅读方式,其余模块也可以参考这样的一个阅读方式。
希望能帮助大家在观看 Node.js 内置 API 时有帮助。