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中自定义事件实例
Jun 20 NodeJs
nodejs教程之环境安装及运行
Nov 21 NodeJs
nodejs简单实现中英文翻译
May 04 NodeJs
快速掌握Node.js之Window下配置NodeJs环境
Mar 21 NodeJs
详解nodejs 文本操作模块-fs模块(二)
Dec 22 NodeJs
nodeJS删除文件方法示例
Dec 25 NodeJs
Nodejs高扩展性的模板引擎 functmpl简介
Feb 13 NodeJs
解析NodeJS异步I/O的实现
Apr 13 NodeJs
nodejs密码加密中生成随机数的实例代码
Jul 17 NodeJs
nodejs中art-template模板语法的引入及冲突解决方案
Nov 07 NodeJs
nodejs基于WS模块实现WebSocket聊天功能的方法
Jan 12 NodeJs
Nodejs模块的调用操作实例分析
Dec 25 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 SQL Injection with MySQL
2011/02/27 PHP
php中的观察者模式简单实例
2015/01/20 PHP
搭建Vim为自定义的PHP开发工具的一些技巧
2015/12/11 PHP
Javascript 原型和继承(Prototypes and Inheritance)
2009/04/01 Javascript
jQuery队列控制方法详解queue()/dequeue()/clearQueue()
2010/12/02 Javascript
弹出层之1:JQuery.Boxy (一) 使用介绍
2011/10/06 Javascript
node.js中的fs.exists方法使用说明
2014/12/17 Javascript
JavaScript中的全局对象介绍
2015/01/01 Javascript
jQuery+canvas实现简单的球体斜抛及颜色动态变换效果
2016/01/28 Javascript
AngularJS基础 ng-open 指令简单实例
2016/08/02 Javascript
原生JS实现网络彩票投注效果
2016/09/25 Javascript
微信小程序 图片宽度自适应的实现
2017/04/06 Javascript
利用Jasmine对Angular进行单元测试的方法详解
2017/06/12 Javascript
微信小程序实现列表下拉刷新上拉加载
2020/07/29 Javascript
Element Table的row-class-name无效与动态高亮显示选中行背景色
2018/11/30 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
Vue实现多标签选择器
2019/11/28 Javascript
vue 将多个过滤器封装到一个文件中的代码详解
2020/09/05 Javascript
Python编程中对super函数的正确理解和用法解析
2016/07/02 Python
查看Django和flask版本的方法
2018/05/14 Python
Window 64位下python3.6.2环境搭建图文教程
2018/09/19 Python
Python实现最常见加密方式详解
2019/07/13 Python
使用Python脚本zabbix自定义key监控oracle连接状态
2019/08/28 Python
python中查看.db文件中表格的名字及表格中的字段操作
2020/07/07 Python
CSS3 边框效果
2019/11/04 HTML / CSS
波兰香水和化妆品购物网站:Notino.pl
2017/11/07 全球购物
写给女朋友的道歉信
2014/01/12 职场文书
小学生红领巾广播稿
2014/01/21 职场文书
大学生活动策划方案
2014/02/10 职场文书
我爱我家教学反思
2014/05/01 职场文书
餐饮服务食品安全责任书
2014/07/25 职场文书
2016年大学生就业指导课心得体会
2015/10/09 职场文书
2016中秋节晚会开场白
2015/11/26 职场文书
公司周年庆寄语
2019/06/21 职场文书
python爬虫之selenium库的安装及使用教程
2021/05/23 Python
JavaScript中document.activeELement焦点元素介绍
2021/11/27 Javascript