阅读工具
以下内容是基于node15.14.0版本阅读的。另外在github仓库的地址上github后面加上 1s
可以在网页上利用vscode查看源码,支持快捷方式文件跳转,全局搜索等。
Node启动过程
- 调用node::Start (node_main.cc)
- 构建main_instance并run (node.cc) 这过程中包含libuv的配置,以及v8平台
- LoadEnvironment (node_main_instance.cc) 在这个期间进行libuv的初始化
- StartExecution (environment.cc)
- 会执行一些脚本,其中包含
StartExecution(env, "internal/main/run_main_module")
就是执行我们在命令行启动时携带的参数脚本
Node的各种模块
先来介绍个概念,经常能看到 binding
在代码中,以下是摘自 learncpp.com
Binding refers to the process that is used to convert identifiers (such as variable and function names) into addresses. Although binding is used for both variables and functions, in this lesson we’re going to focus on function binding
就是把各种标识符编译到具体地址,这样比如在js中的就可以获取到一个在内存中的c++方法的地址进而可以调用。
C++内置模块
不对用户暴露的模块,比如 v8
, libuv
, fs
, 这些模块。在 node_binding.cc
有内置模块的列表;这些模块在node内部通关 internalBinding
绑定,这些模块会在各自模块的结尾调用 NODE_MODULE_CONTEXT_AWARE_INTERNAL
创建绑定。
C++外部模块
编写c++插件的模块就算外部模块,这些模块是通过动态链接对象添加到当前环境的,这个模块就是一个的动态链接库,相当于windows下的 *.dll
以及 macOS 下的 *.dylib
. 这些模块一样需要在自己的代码底部利用node提供的宏 NODE_MODULE
, NODE_MODULE_INITIALIZER
等进行注册。
js原生模块
这些模块在node项目中的 lib/**/*.js
以及 dep/**/*.js
位置。这些模块就是我们通过node的api引入的模块例如 fs
, http
等,这些模块其实是将c++模块包了一层暴露给用户调用,这些模块会在node项目编译的时候被利用 [js2c.py](http://js2c.py)
生成的 node_javascript.cc
打入node二进制文件中,所以这些文件调用的时候是没有I/O损耗的。
js用户模块
这部分模块是用户编写包含npm中的第三方模块,这些模块在引用时,这些模块就是通过node的 fs
模块进行加载,并且进入缓存。在 /lib/internal/modules/cjs/loader.js
文件中我们可以看到如下代码,实际上我们的代码就是把这两块包裹这的一个闭包,node借此实现了模块的功能。
const wrapper = [
'(function (exports, require, module, __filename, __dirname) { ',
'\n});',
];
复制代码
小结
因为刚学完c++,所以就立马来看看相关的项目,正好看到死月的《Node.js: 来一打C++扩展》,所以就拜读了一下。我的初衷本来是应该要熟悉C++并且借机学点node的东西,但是看到后来发现自己深入到细节中去,而且死抠代码细节,所以这篇文章写起来感觉好像也没什么收获,我只是知道了一些事实,不知道为什么这么做,这么做的原因o(╯□╰)o. 我打算应该多去了解些“为什么”,而不是“是什么”。