node.js 模块加载机制

核心模块(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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值