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 win7下安装方法
May 24 NodeJs
nodejs中exports与module.exports的区别详细介绍
Jan 14 NodeJs
用nodejs写的一个简单项目打包工具
May 11 NodeJs
nodejs中的fiber(纤程)库详解
Mar 24 NodeJs
nodejs的HTML分析利器node-jquery用法浅析
Nov 08 NodeJs
使用nodejs下载风景壁纸
Feb 05 NodeJs
详解nodejs微信公众号开发——1.接入微信公众号
Apr 10 NodeJs
详解如何在NodeJS项目中优雅的使用ES6
Apr 22 NodeJs
nodejs 最新版安装npm 的使用详解
Jan 18 NodeJs
NodeJS父进程与子进程资源共享原理与实现方法
Mar 16 NodeJs
解决nodejs的npm命令无反应的问题
May 17 NodeJs
Nodejs异步回调之异常处理实例分析
Jun 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
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
2015/04/08 PHP
PHP生成唯一订单号的方法汇总
2015/04/16 PHP
中高级PHP程序员应该掌握哪些技术?
2016/09/23 PHP
php实现留言板功能(会话控制)
2017/05/23 PHP
javascript之ESC(第二类混淆)
2007/05/06 Javascript
js 弹出框只弹一次(二次修改之后的)
2013/11/26 Javascript
JavaScript中的函数的两种定义方式和函数变量赋值
2014/05/12 Javascript
jquery插件qrcode在线生成二维码
2015/04/26 Javascript
通用javascript代码判断版本号是否在版本范围之间
2015/11/29 Javascript
Vue.js组件tree实现省市多级联动
2016/12/02 Javascript
如何制作一个Node命令行图像识别工具
2018/12/12 Javascript
对node通过fs模块判断文件是否是文件夹的实例讲解
2019/06/10 Javascript
vue cli3 调用百度翻译API翻译页面的实现示例
2019/09/13 Javascript
vuex的使用和简易实现
2021/01/07 Vue.js
[02:31]DOTA2帕克 英雄基础教程
2013/11/26 DOTA
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
使用django-suit为django 1.7 admin后台添加模板
2014/11/18 Python
Python中用sleep()方法操作时间的教程
2015/05/22 Python
Python实现针对json中某个关键字段进行排序操作示例
2018/12/25 Python
Python设计模式之迭代器模式原理与用法实例分析
2019/01/10 Python
基于Django静态资源部署404的解决方法
2019/07/28 Python
python try except返回异常的信息字符串代码实例
2019/08/15 Python
python字符串反转的四种方法详解
2019/12/02 Python
解决pycharm 安装numpy失败的问题
2019/12/05 Python
django实现HttpResponse返回json数据为中文
2020/03/27 Python
Python爬虫爬取、解析数据操作示例
2020/03/27 Python
澳大利亚厨房和家用电器购物网站:Bing Lee
2021/01/11 全球购物
采购主管工作职责
2013/12/12 职场文书
初中校园广播稿
2014/02/02 职场文书
如何写好建议书
2014/03/13 职场文书
《第一朵杏花》教学反思
2014/04/16 职场文书
支部鉴定材料
2014/06/02 职场文书
无锡灵山大佛导游词
2015/02/09 职场文书
安全知识竞赛主持词
2015/06/30 职场文书
详解Mysql和Oracle之间的误区
2021/05/18 MySQL