CommonJS规范 

   
早于Netscape诞生快晚,JavaScript就径直于探究本地编程的路程,Rhino是其象征产物。无奈那时服务端JavaScript走的程皆是参照众多劳动器端语言来实现的,在这样的背景之下,一没有特色,二无实用价值。但是随着JavaScript在前者的使用更加广泛,以及服务端JavaScript的推进,JavaScript现有的正儿八经大娇生惯养,不便于JavaScript大规模的运用。那些以JavaScript为宿主语言的环境遭到,只有我的根基原生对象同种,更多之目标及API都在宿主的供,所以,我们可以看JavaScript缺少这些意义:

  • JavaScript没有模块系统。没有原生的支撑密闭作用域或因管理。 
  • JavaScript没有标准库。除了有些主导库外,没有文件系统的API,没有IO流API等。 
  • JavaScript没有标准接口。没有如Web Server或者数据库的集合接口。 
  • JavaScript没有管教管理体系。不能自动加载与安依赖。 

   
于是便出矣CommonJS(http://www.commonjs.org)规范的出现,其目标是为了构建JavaScript在包括Web服务器,桌面,命令行工具,及浏览器方面的生态系统。CommonJS制定了解决这些问题的一些规范,而Node.js就是这些规范的一种实现。Node.js自身实现了require方法作为其引入模块的方法,同时NPM也基于CommonJS定义的包规范,实现了依赖管理和模块自动安装等功能。这里我们将深入一下Node.js的require机制和NPM基于包规范的应用。

 

简短模块定义及利用

   
在Node.js中,定义一个模块十分有利。我们为计算圆形的面积及周长两独点子为例,来见Node.js中模块的概念方式。

1 var PI = Math.PI; 
2 exports.area = function (r) {
3  return PI * r * r; 
4 }; 
5 exports.circumference = function (r) {
6  return 2 * PI * r; 
7 };

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

1 var circle = require('./circle.js'); 
2 console.log( 'The area of a circle of radius 4 is ' + circle.area(4));

   
可以视模块调用也要命便于,只待require需要调用的文书即可。

   
在require了此文件从此,定义在exports对象及之主意就可无限制调用。Node.js将模块的概念和调用都打包得最好简约好,从API对用户自己这一个角度来说,Node.js的模块机制是大了不起之。

 

模块载入策略

   
Node.js的模块分为两看似,一像样为原生(核心)模块,一近似为文件模块。原生模块于Node.js源代码编译的下编译进了第二上制实行文书,加载的速最好抢。另一样看似公事模块是动态加载的,加载速度较原生模块慢。但是Node.js对原生模块和文件模块都进展了缓存,于是以其次浅require时,是未会见时有发生重开发的。其中原生模块都为定义在lib这个目录下面,文件模块则不定性。

node app.js

   
由于通过命令行加载启动之文书几乎都为文件模块。我们于Node.js如何加载文件模块开始讲话起。加载文件模块的做事,主要出于原生模块module来贯彻和就,该原生模块于起步时都深受加载,进程一直调用到runMain静态方法。

1 // bootstrap main module. 
2 Module.runMain = function () {
3     // Load the main module--the command line argument. 
4     Module._load(process.argv[1], null, true); 
5 };

   
_load静态方法在条分缕析文件称自此执行

var module = new Module(id, parent);

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

module.load(filename);

   
实际上在文书模块中,又分为3类模块。这三近乎公事模块然后缀来分别,Node.js会根据后缀名来决定加载方法。

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

   
这里我们用详细描述js后缀的编译过程。Node.js在编译js文件之经过遭到实际上到位的步调有对js文件内容开展头尾包装。

    以app.js为例,包装后的app.js将会化为以下形式:

1 (function (exports, require, module, __filename, __dirname) { 
2     var circle = require('./circle.js');
3     console.log('The area of a circle of radius 4 is ' + circle.area(4)); 
4 });

   
这段代码会通过vm原生模块的runInThisContext方法执行(类似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中。

 

相关文章

网站地图xml地图