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使用mysql模块之获得更新和删除影响的行数的方法
Mar 18 NodeJs
14款NodeJS Web框架推荐
Jul 11 NodeJs
浅谈NodeJS中require路径问题
May 07 NodeJs
nodejs实现遍历文件夹并统计文件大小
May 28 NodeJs
nodejs实例解析(输出hello world)
Jan 03 NodeJs
nodejs搭建本地服务器并访问文件的方法
Mar 03 NodeJs
NodeJs的fs读写删除移动监听
Apr 28 NodeJs
nodejs socket服务端和客户端简单通信功能
Sep 14 NodeJs
nodejs实现解析xml字符串为对象的方法示例
Mar 14 NodeJs
NodeJS搭建HTTP服务器的实现步骤
Oct 12 NodeJs
Nodejs 识别图片类型的方法
Aug 15 NodeJs
nodejs中使用worker_threads来创建新的线程的方法
Jan 22 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
用DBSQL类加快开发MySQL数据库程序的速度
2006/10/09 PHP
php中$_REQUEST、$_POST、$_GET的区别和联系小结
2011/11/23 PHP
PHP自动载入类文件函数__autoload的使用方法
2019/03/25 PHP
用js怎么把&字符换成"&amp:"
2006/10/19 Javascript
几个常用的JavaScript字符串处理函数 - split()、join()、substring()和indexOf()
2009/06/02 Javascript
javascript实现div的显示和隐藏的小例子
2013/06/25 Javascript
JS中的log对象获取以及debug的写法介绍
2014/03/03 Javascript
javascript闭包传参和事件的循环绑定示例探讨
2014/04/17 Javascript
使用jquery animate创建平滑滚动效果(可以是到顶部、到底部或指定地方)
2014/05/27 Javascript
JavaScript动态改变HTML页面元素例如添加或删除
2014/08/10 Javascript
javascript解决IE6下hover问题的方法
2015/07/28 Javascript
学习掌握JavaScript中this的使用技巧
2016/08/29 Javascript
使用纯JS代码判断字符串中有多少汉字的实现方法(超简单实用)
2016/11/12 Javascript
js点击任意区域弹出层消失实现代码
2016/12/27 Javascript
bootstrap提示标签、提示框实现代码
2016/12/28 Javascript
js实现前端分页页码管理
2017/01/06 Javascript
jQuery插件echarts设置折线图中折线线条颜色和折线点颜色的方法
2017/03/03 Javascript
bootstrap-table组合表头的实现方法
2017/09/07 Javascript
[01:02:18]VGJ.S vs infamous Supermajor 败者组 BO3 第一场 6.4
2018/06/05 DOTA
python文件和目录操作方法大全(含实例)
2014/03/12 Python
spark: RDD与DataFrame之间的相互转换方法
2018/06/07 Python
python仿evething的文件搜索器实例代码
2019/05/13 Python
python图像和办公文档处理总结
2019/05/28 Python
Python正则表达式急速入门(小结)
2019/12/16 Python
css3学习之2D转换功能详解
2016/12/23 HTML / CSS
纯CSS实现菜单、导航栏的3D翻转动画效果
2014/04/23 HTML / CSS
Wiggle中国:英国骑行、跑步、游泳 & 铁三运动装备专卖网店
2016/08/02 全球购物
GAP美国官网:美国休闲时尚品牌
2016/08/26 全球购物
意大利奢侈品牌在线精品店:Jole.it
2020/11/23 全球购物
家长对孩子评语
2014/01/30 职场文书
护理专业自我鉴定
2014/01/30 职场文书
退伍老兵事迹材料
2014/01/31 职场文书
我的中国梦演讲稿1000字
2014/08/19 职场文书
人事任命书范本
2015/09/21 职场文书
Python中glob库实现文件名的匹配
2021/06/18 Python
MySQL普通表如何转换成分区表
2022/05/30 MySQL