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和PhantomJS抓取网站页面信息以及网站截图
Nov 18 NodeJs
nodejs获取本机内网和外网ip地址的实现代码
Jun 01 NodeJs
nodejs爬虫抓取数据之编码问题
Jul 03 NodeJs
详解nodeJS中读写文件方法的区别
Mar 06 NodeJs
详解如何在NodeJS项目中优雅的使用ES6
Apr 22 NodeJs
nodejs接入阿里大鱼短信验证码的方法
Jul 10 NodeJs
Windows下快速搭建NodeJS本地服务器的步骤
Aug 09 NodeJs
详解nodeJs文件系统(fs)与流(stream)
Jan 24 NodeJs
关于Mac下安装nodejs、npm和cnpm的教程
Apr 11 NodeJs
详解微信小程序-获取用户session_key,openid,unionid - 后端为nodejs
Apr 29 NodeJs
基于NodeJS开发钉钉回调接口实现AES-CBC加解密
Aug 20 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程序--记数器
2006/10/09 PHP
PHP文件读取功能的应用实例
2015/05/08 PHP
简单理解PHP的面向对象编程方式
2016/05/17 PHP
完美解决在ThinkPHP控制器中命名空间的问题
2017/05/05 PHP
Laravel框架使用Redis的方法详解
2018/05/30 PHP
laravel 实现向公共模板中传值 (view composer)
2019/10/22 PHP
js实现的日期操作类DateTime函数代码
2010/03/16 Javascript
javascript使用activex控件的代码
2011/01/27 Javascript
node.js chat程序如何实现Ajax long-polling长链接刷新模式
2012/03/13 Javascript
基于jQuery的遍历同id元素 并响应事件的代码
2012/06/14 Javascript
replace()方法查找字符使用示例
2013/10/28 Javascript
jQuery中:contains选择器用法实例
2014/12/30 Javascript
基于jquery实现左右按钮点击的图片切换效果
2021/01/27 Javascript
gameboy网页闯关游戏(riddle webgame)--仿微信聊天的前端页面设计和难点
2016/02/21 Javascript
老生常谈原生JS执行环境与作用域
2016/11/22 Javascript
JS实现中英文混合文字溢出友好截取功能
2018/08/06 Javascript
Vue CLI3 如何支持less的方法示例
2018/08/29 Javascript
小程序扫描普通链接二维码跳转小程序指定界面方法
2019/05/07 Javascript
在Chrome DevTools中调试JavaScript的实现
2020/04/07 Javascript
Vue中正确使用Element-UI组件的方法实例
2020/10/13 Javascript
深入探究Django中的Session与Cookie
2017/07/30 Python
tensorflow TFRecords文件的生成和读取的方法
2018/02/06 Python
python跳出双层for循环的解决方法
2019/06/24 Python
Python Django2.0集成Celery4.1教程
2019/11/19 Python
使用Python串口实时显示数据并绘图的例子
2019/12/26 Python
Python random模块的使用示例
2020/10/10 Python
html5中如何将图片的绝对路径转换成文件对象
2018/01/11 HTML / CSS
天美时手表加拿大官网:Timex加拿大
2016/09/01 全球购物
英国剑桥包中文官网:The Cambridge Satchel Company中国
2018/11/06 全球购物
安全的后院和健身蹦床:JumpSport
2019/07/15 全球购物
北美最大的零售退货翻新商:VIP Outlet
2019/11/21 全球购物
英国标志性生活方式品牌:Skinnydip London
2019/12/15 全球购物
2016应届大学生自荐信模板
2016/01/28 职场文书
python实现MD5进行文件去重的示例代码
2021/07/09 Python
MySQL创建表操作命令分享
2022/03/25 MySQL
Mysql将字符串按照指定字符分割的正确方法
2022/05/30 MySQL