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教程 安装express及配置app.js文件的详细步骤
May 11 NodeJs
Nodejs中自定义事件实例
Jun 20 NodeJs
基于NodeJS的前后端分离的思考与实践(四)安全问题解决方案
Sep 26 NodeJs
nodejs加密Crypto的实例代码
Jul 07 NodeJs
angular2+nodejs实现图片上传功能
Mar 27 NodeJs
Nodejs实现多房间简易聊天室功能
Jun 20 NodeJs
nodejs结合Socket.IO实现的即时通讯功能详解
Jan 12 NodeJs
Linux Centos7.2下安装nodejs&npm配置全局路径的教程
May 15 NodeJs
nodejs检测因特网是否断开的解决方案
Apr 17 NodeJs
详解微信小程序-获取用户session_key,openid,unionid - 后端为nodejs
Apr 29 NodeJs
基于NodeJS开发钉钉回调接口实现AES-CBC加解密
Aug 20 NodeJs
Nodejs + sequelize 实现增删改查操作
Nov 07 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
回答PHPCHINA上的几个问题:URL映射
2007/02/14 PHP
浅析使用Turck-mmcache编译来加速、优化PHP代码
2013/06/20 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十四)
2014/06/26 PHP
简要剖析PHP的Yii框架的组件化机制的基本知识
2016/03/17 PHP
php微信开发之自定义菜单实现
2016/11/18 PHP
在js中单选框和复选框获取值的方式
2009/11/06 Javascript
js null undefined 空区别说明
2010/06/13 Javascript
JavaScript类和继承 prototype属性
2010/09/03 Javascript
javascript中判断json的方法总结
2015/08/27 Javascript
js的form表单提交url传参数(包含+等特殊字符)的两种解决方法
2016/05/25 Javascript
jQuery模拟select实现下拉菜单功能
2016/06/20 Javascript
js实现选项卡内容切换以及折叠和展开效果【推荐】
2017/01/08 Javascript
浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序
2017/02/19 Javascript
JS实现读取xml内容并输出到div中的方法示例
2018/04/19 Javascript
nodejs对项目下所有空文件夹创建gitkeep的方法
2019/08/02 NodeJs
Vue微信公众号网页分享的示例代码
2020/05/28 Javascript
python列表与元组详解实例
2013/11/01 Python
玩转python爬虫之cookie使用方法
2016/02/17 Python
python 实现删除文件或文件夹实例详解
2016/12/04 Python
初学python的操作难点总结(新手必看篇)
2017/08/03 Python
Python操作MongoDB数据库的方法示例
2018/01/04 Python
python实现K最近邻算法
2018/01/29 Python
python实现扫描日志关键字的示例
2018/04/28 Python
Python 爬取携程所有机票的实例代码
2018/06/11 Python
HTML+CSS3+JS 实现的下拉菜单
2020/11/25 HTML / CSS
使用HTML5中的contentEditable来将多行文本自动增高
2016/03/01 HTML / CSS
波兰汽车配件网上商店:iParts.pl
2020/09/08 全球购物
武汉世纪畅想数字传播有限公司.NET笔试题
2014/07/22 面试题
文明礼貌演讲稿
2014/05/12 职场文书
红领巾广播站广播稿
2014/10/19 职场文书
新郎新娘答谢词
2015/01/04 职场文书
项目经理助理岗位职责
2015/04/13 职场文书
2015国庆节66周年标语
2015/07/30 职场文书
聘任合同书
2015/09/21 职场文书
2016年“六一儿童节”校园广播稿
2015/12/17 职场文书
2016年幼儿园教师师德承诺书
2016/03/25 职场文书