您的位置:首页 > Web前端 > Node.js

node.js 模块加载机制

2013-11-16 13:06 417 查看


核心模块(Core modules)

node中有一些模块被编译成二进制.

核心模块被定义在node的源码中的lib文件夹下。

如果核心模块的标识符被传入require()方法时,总是被优先加载.例如,require(‘http’)将总是返回内置的http模块,即使当前有一个同名的模块文件夹。


文件模块加载机制(File modules)

如果准确的文件名字没有找到,node将会试图依次加载添加了.js,.json,.node等后缀名的文件.

.js文件被当作javascript文本文件解读,.json文件被转换成json文本文件. .node文件被当做已经编译好的插件模块,使用dloopen加载.(在dlopen()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。)

当一个模块的前缀是“/”时,表示一个模块文件的绝对路径.例如:require(‘/home/marco/foo.js’)将会使用‘/home/marco/foo.js’作为路径加载.

当一个模块的前缀是“./”时,表示一个模块文件的相对路径调用require().例如:为了让foo.js中的require(‘./circle.js’)能被找到,circle.js必须和foo.js在同一目录下.

如果没有“./”或者“/”当文件前缀,这个模块不是一个核心模块,就是一个需要从node_modules文件夹中加载的模块.

如果给定的加载路径不存在,requier()方法将会抛出一个Error错误对象,并且Error的code属性被设置成:'MODULE_NOT_FOUND'.


从node_modules文件夹加载模块(loading from node_mudoles folde

如果传入到require()方法中的模块标识符不是本地模块,并且也不是“/”,“../”,或者“./”开头,node则会在当前模块的父目录路径上追加/node_modules,以这个路径试图加载模块.

如果这里也没有找到,node会继续移动到更上一层的父目录,等等…直到到达根目录.

例如,文件‘/home/ry/project/foo.js’中调用require(‘bar.js’),node会查找以下列出的路径,依次是:

/home/ry/projects/node_modules/bar.js

/home/ry/node_modules/bar.js

/home/node_modules/bar.js

/node_modules/bar.js

这将允许程序本地化他们的依赖,以便不产生冲突.


文件夹就是模块(Floder as modules)

组织程序和类库放进自己包含的目录下是很方便的,然后提供一个单独的入口指定这个类库,有三种方法把一个文件夹作为一个参数传进require()方法.

第一种方法是在根目录创建一个package.json文件,指定一个主模块.一个paceage.json的例子看起来像这样子:
{ "name" : "some-library",
"main" : "./lib/some-library.js" }


如果当前程序路径是在./some-library目录下,则require(‘./some-library’)将会试图加载路径./some-library/lib/some-library.js.

这是node自动拓展自package.json文件的结果.

如果这个目录下没有出现package.json文件,node将会试图在这个目录加载一个index.js或者index.node文件出来.例如,如果在上面的例子中没有package.json文件,则require(‘./sone-library’)将会试图加载:

./some-library/index.js

./some-library/index.node


缓存(Caching)

当模块被第一次加载之后就被缓存了起来,这意味着在其他地方调用require(‘foo’)将会获得一样一样的对象被返回,如果他们扫描的是同一文件的情况下.

多次调用require(‘foo’)不会引起模块代码被执行多次.这是一个重要的特性.有了它,部分加载完成的对象可以被返回,进而允许加载过渡期的依赖对象,甚至当他们引起环形加载.


缓存模块提醒(Module Caching caveats)

模块是以他们被解析出的文件名称为基础缓存起来的,因为模块可能由于调用require()方法的当前路径不一样,而导致解析出不一样的文件名称,(从node_modules文件夹加载),如果解析出不同的文件,将不能保证require(‘foo’)总是会返回一致的对象.


module对象(The module Object)

在每一个模块中,自由变量module是一个代表当前模块的引用.因此module.exports和exports对象是一样的.module实际上不是一个全局变量,但是内置于每一个模块中.


module.exports

exports对象是被模块机制创建的,有时候,许多情况需要让模块成为一些类的一个实例,而使exports不可访问,为了把渴望导出的对象分配给moduel.exports对象,在例子中假设我们需要编写一个a.js模块。
var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();
// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(function() {
module.exports.emit('ready');
}, 1000);


在另一个文件里我们需要做:
var a = require('./a');
a.on('ready', function() {
console.log('module a is ready');
});


注意,这种分配对象到module.exports对象的操作一定要立刻执行,如果放在任何一个回调函数里面,将不会生效.

vi x.js
setTimeout(function() {
module.exports = { a: "hello" };
}, 0);


vi y.js
var x = require('./x');
console.log(x.a);  // undefined


module.require(id)

id
String

return:从解析出的模块中导出的对象.

module.require()方法提供了一种方式去加载一个在之前已经加载的模块.

注意,为了实现这种方式,你必须获得一个这个模块的索引,自从require()方法返回了exports对象之后,这个模块只是在这个一段指定的代码里有效,为了使用你需要要明确的导出他.


module.id

String

模块的标识符,是一个能代表模块的完整路径


module.filename

String

一个能代表模块的完整路径


module.loaded

boolean

代表这个模块是加载完成还是正在加载中.


module.parent

module object

代表加载当前模块的模块.


module.children

Array

代表当前模块加载的子模块.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JavaScript node.js 模块