Nodejs模块载入运行原理


Posted in NodeJs onFebruary 23, 2018

前言

使用Nodejs,就不可避免地引用第三方模块,它们有些是Nodejs自带的(例:http,net...),有些是发布在npm上的(例:mssql,elasticsearch...)

本篇章聚焦3个问题:

  1. Nodejs模块的加载过程。
  2. 应用启动的过程。
  3. 应用如何加载依赖模块。

1.模块的加载过程

Nodejs 模块大概可分为4种:

a) builtin module Nodejs中以C++形式提供的模块。

b) constant module Nodejs中定义常量的模块。

c) native module Nodejs中以javascript形式提供的模块。

d) 第三方module 由第三方提供的模块。

我们先看builtin module 和 native module的生成过程。

Nodejs模块载入运行原理

native JS module的生成相对复杂一些,编译后,会在/out/release/obj/gen目录下生成一个node_natives.h。

该文件是由js2c.py生成,它会把Nodejs源码中的lib目录下,所有js文件转成ASCII码,并存放在相应的数组里。

Nodejs模块载入运行原理

builtin C++ module 生成过程相对简单,每个builtin C++的模块入口,都会通过宏NODE_MODULE_CONTEXT_AWARE_BUILTIN扩展成一个func,例如对tcp_wrap模块而言,会扩展成static void register_tcp_wrap() attribute(constructor) 函数。

熟悉GCC的朋友都知道,attribute(constructor)修饰的函数会在Nodejs的main()函数之前被执行,也就是说,builtin C++ module 会在main()函数之前被载入到modlist_builtin列表,而modlist_builtin是一个struct node_module类型的指针,get_builtin_module()会遍历查找我们所需的模块。

其实无论是naive JS module 还是 builtin C++ module,最终都是要被编译成可执行文件。对于两者的提取方式,却大不相同,js module 使用process.binding('natives'),而C++ module 则直接使用get_builtin_module()。

在node.cc里面提供了一个binding()函数,当我们应用require()来引用另外一个模块时,binding()函数便会被引入。下面我们分析一下这个函数:

Nodejs模块载入运行原理

可以目测到,函数主要为三个模块服务:builtin,constants和native。

builtin优先级最高,会到modlist_builtin中查找,过程非常简单,遍历整个列表,查找相同名字的模块即可。找到后,模块的注册函数会被先执行,然后将数据exports返回。

constants模块优先级次之,Nodejs中的常量定义通过constants导出。

native 优先级最低。

2.应用启动的过程

Nodejs模块载入运行原理

上图为一个流程图,它描述了test.js做为参数启动开始,最终被执行。整个过程可以分为4步:

1.可执行文件 node : node入口,在启动过程中主要扮演环境准备工作

2.src/node.js:启动脚本

3.Native Module:为module.js 的执行做准备工作

4.module.js:native module,用来加载,编译,执行应用程序

应用如何加载依赖模块

前面提到NativeModule.require()只负责帮助引用natives module,这对于lib/module.js而言已经足够了。

但是很明显,一般应用不但需要引用matives module,还要引用第三方模块,让我们看一下module.js中的Module.prototype._require()函数中。

Nodejs模块载入运行原理

NodeJs 相关文章推荐
Nodejs极简入门教程(二):定时器
Oct 25 NodeJs
nodeJs爬虫获取数据简单实现代码
Mar 29 NodeJs
NodeJs的优势和适合开发的程序
Aug 14 NodeJs
nodejs搭建本地http服务器教程
Mar 13 NodeJs
详解nodejs微信公众号开发——4.自动回复各种消息
Apr 11 NodeJs
Nodejs读取文件时相对路径的正确写法(使用fs模块)
Apr 27 NodeJs
详解nodejs模板引擎制作
Jun 14 NodeJs
Mac 安装 nodejs方法(图文详细步骤)
Oct 30 NodeJs
nodejs爬虫初试superagent和cheerio
Mar 05 NodeJs
Nodejs实现爬虫抓取数据实例解析
Jul 05 NodeJs
nodejs分离html文件里面的js和css的方法
Apr 09 NodeJs
NodeJS配置CORS实现过程详解
Dec 02 NodeJs
Nodejs下使用gm圆形裁剪并合成图片的示例
Feb 22 #NodeJs
nodejs微信扫码支付功能实现
Feb 17 #NodeJs
nodejs+express搭建多人聊天室步骤
Feb 12 #NodeJs
nodeJs实现基于连接池连接mysql的方法示例
Feb 10 #NodeJs
NodeJS简单实现WebSocket功能示例
Feb 10 #NodeJs
nodejs使用redis作为缓存介质实现的封装缓存类示例
Feb 07 #NodeJs
nodejs中Express与Koa2对比分析
Feb 06 #NodeJs
You might like
收藏的PHP常用函数 推荐收藏保存
2010/02/21 PHP
简介PHP的Yii框架中缓存的一些高级用法
2016/03/29 PHP
对于Laravel 5.5核心架构的深入理解
2018/02/22 PHP
Yii框架where查询用法实例分析
2019/10/22 PHP
PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
2020/02/16 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
jQuery 白痴级入门教程
2009/11/11 Javascript
jquery日历插件datepicker用法分析
2016/01/22 Javascript
Javascript中的数组常用方法解析
2016/06/17 Javascript
浅谈键盘上回车按钮的js触发事件
2017/02/13 Javascript
微信小程序商城项目之商品属性分类(4)
2017/04/17 Javascript
js实现移动端导航点击自动滑动效果
2017/07/18 Javascript
Javascript实现运算符重载详解
2018/04/07 Javascript
超出JavaScript安全整数限制的数字计算BigInt详解
2018/06/24 Javascript
python实现文件快照加密保护的方法
2015/06/30 Python
浅析Python中signal包的使用
2015/11/13 Python
解决安装python库时windows error5 报错的问题
2018/10/21 Python
Python脚本完成post接口测试的实例
2018/12/17 Python
实例详解Python装饰器与闭包
2019/07/29 Python
python 对一幅灰度图像进行直方图均衡化
2020/10/27 Python
python urllib和urllib3知识点总结
2021/02/08 Python
灵活运用CSS3特性绘制简易版围棋效果
2016/09/28 HTML / CSS
为什么要有struct关键字
2012/05/08 面试题
财务会计应届生求职信
2013/11/24 职场文书
学校岗位设置方案
2014/01/16 职场文书
《自选商场》教学反思
2014/02/14 职场文书
学生打架检讨书
2014/10/20 职场文书
优秀班主任申报材料
2014/12/16 职场文书
农民工工资支付承诺书
2015/05/04 职场文书
建筑工程催款函
2015/06/24 职场文书
运动会三级跳加油稿
2015/07/21 职场文书
2016年幼儿园教师政治学习心得体会
2016/01/23 职场文书
Python数据分析之pandas函数详解
2021/04/21 Python
python使用glob检索文件的操作
2021/05/20 Python
Python正则表达式中flags参数的实例详解
2022/04/01 Python
vue修饰符.capture和.self的区别
2022/04/22 Vue.js