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
nodejs获取本机内网和外网ip地址的实现代码
Jun 01 NodeJs
NodeJs中的VM模块详解
May 06 NodeJs
详解nodejs 文本操作模块-fs模块(五)
Dec 23 NodeJs
nodeJs链接Mysql做增删改查的简单操作
Feb 04 NodeJs
nodejs6下使用koa2框架实例
May 18 NodeJs
基于nodejs+express4.X实现文件下载的实例代码
Jul 13 NodeJs
nodejs简单读写excel内容的方法示例
Mar 16 NodeJs
nodejs用gulp管理前端文件方法
Jun 24 NodeJs
webpack打包nodejs项目的方法
Sep 26 NodeJs
NodeJs入门教程之定时器和队列
Mar 08 NodeJs
通过实例了解Nodejs模块系统及require机制
Jul 16 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动态生成静态HTML网页的代码
2010/03/04 PHP
Thinkphp自定义代码生成工具及用法说明(附下载地址)
2016/05/27 PHP
javascript 解决表单仍然提交即使监听处理函数返回false
2010/03/14 Javascript
使用jQuery validate 验证注册表单实例演示
2013/03/25 Javascript
jquery 获取标签名(tagName)示例代码
2013/07/11 Javascript
jquery ajax应用中iframe自适应高度问题解决方法
2014/04/12 Javascript
JS实现超简单的鼠标拖动效果
2015/11/02 Javascript
JS数组合并push与concat区别分析
2015/12/17 Javascript
学习jQuey中的return false
2015/12/18 Javascript
jQuery事件绑定on()与弹窗实现代码
2016/04/28 Javascript
JS简单获取客户端IP地址的方法【调用搜狐接口】
2016/09/05 Javascript
gulp教程_从入门到项目中快速上手使用方法
2017/09/14 Javascript
vue axios登录请求拦截器
2018/04/02 Javascript
国内常用的js类库大全(CDN公共库)
2020/06/24 Javascript
[00:32]2018DOTA2亚洲邀请赛VG出场
2018/04/03 DOTA
Python中的数学运算操作符使用进阶
2016/06/20 Python
使用Python进行二进制文件读写的简单方法(推荐)
2016/09/12 Python
python实现杨辉三角思路
2017/07/14 Python
python3解析库pyquery的深入讲解
2018/06/26 Python
Python使用pymysql从MySQL数据库中读出数据的方法
2018/07/25 Python
Django模板Templates使用方法详解
2019/07/19 Python
pytorch 中的重要模块化接口nn.Module的使用
2020/04/02 Python
20行Python代码实现一款永久免费PDF编辑工具的实现
2020/08/27 Python
selenium+超级鹰实现模拟登录12306
2021/01/24 Python
HTML5标签小集
2011/08/02 HTML / CSS
巴西最大的体育用品商城:Netshoes巴西
2016/11/29 全球购物
英国家喻户晓的折扣商场:TK Maxx
2017/05/26 全球购物
荷兰牛仔裤网上商店:Jeans Centre
2018/04/03 全球购物
北美领先的智能产品购物网站:Wellbots
2018/06/11 全球购物
如何强制垃圾回收
2015/10/06 面试题
公司联欢晚会主持词
2014/03/22 职场文书
离婚协议书的书写要求
2014/09/17 职场文书
电话营销开场白
2015/05/29 职场文书
自愿离婚协议书范本2016
2016/03/18 职场文书
element多个表单校验的实现
2021/05/27 Javascript
Android中的Launch Mode详情
2022/06/05 Java/Android