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异步回调的优雅处理方法
Sep 25 NodeJs
nodejs教程之异步I/O
Nov 21 NodeJs
nodejs中实现阻塞实例
Mar 24 NodeJs
nodejs微信公众号支付开发
Sep 19 NodeJs
windows 下安装nodejs 环境变量设置
Feb 02 NodeJs
NodeJS配置HTTPS服务实例分享
Feb 19 NodeJs
nodejs入门教程一:概念与用法简介
Apr 24 NodeJs
nodejs实现一个word文档解析器思路详解
Aug 14 NodeJs
用Electron写个带界面的nodejs爬虫的实现方法
Jan 29 NodeJs
nodejs微信开发之授权登录+获取用户信息
Mar 17 NodeJs
NodeJS读取分析Nginx错误日志的方法
May 14 NodeJs
nodejs使用Sequelize框架操作数据库的实现
Oct 21 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
生成缩略图
2006/10/09 PHP
ThinkPHP添加更新标签的方法
2014/12/05 PHP
PHP函数shuffle()取数组若干个随机元素的方法分析
2016/04/02 PHP
PHP实现微信小程序人脸识别刷脸登录功能
2018/05/24 PHP
PhpStorm配置Xdebug调试的方法步骤
2019/02/02 PHP
常见的5个PHP编码小陋习以及优化实例讲解
2021/02/27 PHP
jquery 图片预加载 自动等比例缩放插件
2008/12/25 Javascript
jquery如何改变html标签的样式(两种实现方法)
2013/01/16 Javascript
jQuery :first选择器使用介绍
2013/08/09 Javascript
js与jquery获取父元素,删除子元素的两种不同方法
2014/01/09 Javascript
2014最热门的JavaScript代码高亮插件推荐
2014/11/25 Javascript
为JS扩展Array.prototype.indexOf引发的问题及解决办法
2015/01/21 Javascript
jQuery中$.each使用详解
2015/01/29 Javascript
JavaScript中的关联数组问题
2015/03/04 Javascript
jQuery实现大转盘抽奖活动仿QQ音乐代码分享
2015/08/21 Javascript
js剪切板应用clipboardData实例解析
2016/05/29 Javascript
AngularJS指令中的绑定策略实例分析
2016/12/14 Javascript
深入理解JavaScript中的尾调用(Tail Call)
2017/02/07 Javascript
使用Nodejs连接mongodb数据库的实现代码
2017/08/21 NodeJs
详解基于Koa2开发微信二维码扫码支付相关流程
2018/05/16 Javascript
微信小程序实现选项卡效果
2018/11/06 Javascript
JavaScript定时器常见用法实例分析
2019/11/15 Javascript
[02:20]DOTA2中文配音宣传片
2013/05/22 DOTA
[48:46]完美世界DOTA2联赛PWL S2 SZ vs FTD.C 第二场 11.19
2020/11/19 DOTA
python 去除txt文本中的空格、数字、特定字母等方法
2018/07/24 Python
Python实现压缩文件夹与解压缩zip文件的方法
2018/09/01 Python
django框架ModelForm组件用法详解
2019/12/11 Python
Pycharm打开已有项目配置python环境的方法
2020/07/03 Python
小学学雷锋活动总结
2014/04/25 职场文书
警察群众路线对照检查材料思想汇报
2014/10/01 职场文书
信息技术国培研修日志
2015/11/13 职场文书
2019学校运动会开幕词
2019/05/13 职场文书
选对餐饮营销策略,营业额才会上涨
2019/08/27 职场文书
SpringBoot整合MongoDB的实现步骤
2021/06/23 MongoDB
springboot 启动如何排除某些bean的注入
2021/08/02 Java/Android
详解Mysq MVCC多版本的并发控制
2022/04/29 MySQL