深入Node.js 模块机制

(一)简单模块的定义和使用

   定义一个计算圆形的面积和周长的模块,让我们开启node之旅

   

     将这个文件存为circle.js,并新建一个app.js文件,并写入以下代码:

     

     可以看到模块的调用非常的方便,只需要require 需要调用的文件即可

 


(二)模块载入策略(重点)

  Node.js的模块分为两类

  1. 原生(核心)模块
  2. 文件模块 

  原生模块在Node.js源代码编译的时候编译进了二进制执行文件,加载的速度最快。另一类文件模块是动态加载的,加载速度比原生模块慢。但是Node.js对原生模块和文件模块都进行了缓存,于是在第二次require时,是不会有重复开销的。其中原生模块都被定义在lib这个目录下面,文件模块则不定性。

  由于通过命令行加载启动的文件几乎都为文件模块。我们从Node.js如何加载文件模块开始谈起。加载文件模块的工作,主要由原生module来实现和完成,该原生模块在启动是已经被加载,进程直接调用到runMain静态方法。

  

   _load静态方法在分析文件名之后执行

   

   并根据文件路径缓存当前模块对象,该模块实例对象则根据文件名加载。

  

 

  实际上在文件模块中,又分为3类模块。这三类文件模块以后缀来区分,Node.js会根据后缀名来决定加载方法。

  •  .js  通过fs模块同步读取js文件并编译执行。
  •  .node 通过C/C++ 进行编写的Addon。 通过dlopen 方法进行加载。
  •  .json 读取文件,调用JSON.parse解析加载。  

  这里我们将详细描述js后缀的编译过程。Node.js在编译js文件的过程中实际完成的步骤有对js文件内容进行头尾包装。以app.js为例,包装之后的app.js将会变成以下形式。

  

 

   这段代码会通过VM 原生模块 的runlnThisContext方法执行(类似eval,只是具有明确上下文,不污染全局),返回一个具体的function对象。最后传入module对象的exports,require方法,module,文件名,目录名作为实参并执行。

   这就是为什么require并没有定义在app.js文件中,但是这个方法却存在的原因!!!

   从Node.js的API文档中可以看到还有 __filename, __dirname, module , exports 几个没有定义但是却存在的变量。其中 __filename 和  __dirname在查找文件路径的过程中分析得到后传入的。 module变量是这个模块对象自身,exports是在module的构造函数中初始化的一个空对象({},而不是null)

   在这个主文件中,可以通过require方法去引入其余的模块。而其实这个require方法实际调用的就是load方法。

   load方法在载入,编译,缓存了module后,返回module的exports对象。这就是circle.js文件中只有定义在exports对象上的方法才能被外部调用的原因。

   以上所描述的模块载入机制均定义在lib/module.js中。

 


 

(三)require方法中的文件查找策略

   由于Node.js中存在4类模块(原生模块和3中文件模块),尽管require方法及其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。

   

 

 

 

 

 

 

 


 

        进军西南!!!

 

转载于:https://www.cnblogs.com/misscai/p/11542857.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值