Node.js v0.10.18 手册 & 文档
目录
Modules#
稳定度: 5 - 已锁定
Node has a simple module loading system. In Node, files and modules are in
one-to-one correspondence. As an example, foo.js
loads the module
circle.js
in the same directory.
Node有一个简易的模块加载系统。在node中,文件和模块是一一对应的。下面示例是foo.js
加载同一目录下的circle.js
。
The contents of foo.js
:
foo.js
的内容:
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));
The contents of circle.js
:
circle.js
的内容:
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
The module circle.js
has exported the functions area()
and
circumference()
. To export an object, add to the special exports
object.
circle.js
模块输出了area()
和circumference()
两个函数。要输出某个对象,把它加到exports
这个特殊对象下即可。
Note that exports
is a reference to module.exports
making it suitable
for augmentation only. If you are exporting a single item such as a
constructor you will want to use module.exports
directly instead.
注意,exports
是module.exports
的一个引用,只是为了用起来方便。当你想输出的是例如构造函数这样的单个项目,那么需要使用module.exports
。
// 正确输出构造函数
module.exports = MyConstructor;
Variables
local to the module will be private. In this example the variable PI
is
private to circle.js
.
模块内的本地变量是私有的。在这里例子中,PI
这个变量就是circle.js
私有的。
The module system is implemented in the require("module")
module.
模块系统的实现在require("module")
中。
循环#
When there are circular require()
calls, a module might not be
done being executed when it is returned.
当存在循环的require()
调用时,一个模块可能在返回时并不会被执行。
Consider this situation:
考虑这样一种情形:
a.js
:
a.js
:
console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js
:
b.js
:
console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js
:
main.js
:
console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
When main.js
loads a.js
, then a.js
in turn loads b.js
. At that
point, b.js
tries to load a.js
. In order to prevent an infinite
loop an unfinished copy of the a.js
exports object is returned to the
b.js
module. b.js
then finishes loading, and its exports
object is
provided to the a.js
module.
首先main.js
加载a.js
,接着a.js
又去加载b.js
。这时,b.js
会尝试去加载a.js
。为了防止无限的循环,a.js
会返回一个unfinished copy给b.js
。然后b.js
就会停止加载,并将其exports
对象返回给a.js
模块。
By the time main.js
has loaded both modules, they're both finished.
The output of this program would thus be:
这样main.js
就把这两个模块都加载完成了。这段程序的输出如下:
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
If you have cyclic module dependencies in your program, make sure to plan accordingly.
如果你的程序中有循环的模块依赖,请确保工作正常。
核心模块#
Node has several modules compiled into the binary. These modules are described in greater detail elsewhere in this documentation.
Node中有一些模块是编译成二进制的。这些模块在本文档的其他地方有更详细的描述。
The core modules are defined in node's source in the lib/
folder.
核心模块定义在node源代码的lib/
目录下。
Core modules are always preferentially loaded if their identifier is
passed to require()
. For instance, require('http')
will always
return the built in HTTP module, even if there is a file by that name.
require()
总是会优先加载核心模块。例如,require('http')
总是返回编译好的HTTP模块,而不管是否有这个名字的文件。
文件模块#
If the exact filename is not found, then node will attempt to load the
required filename with the added extension of .js
, .json
, and then .node
.
如果按文件名没有查找到,那么node会添加 .js
和 .json
后缀名,再尝试加载,如果还是没有找到,最后会加上.node
的后缀名再次尝试加载。
.js
files are interpreted as JavaScript text files, and .json
files are
parsed as JSON text files. .node
files are interpreted as compiled addon
modules loaded with dlopen
.
.js
会被解析为Javascript纯文本文件,.json
会被解析为JSON格式的纯文本文件. .node
则会被解析为编译后的插件模块,由dlopen
进行加载。
A module prefixed with '/'
is an absolute path to the file. For
example, require('/home/marco/foo.js')
will load the file at
/home/marco/foo.js
.
模块以'/'
为前缀,则表示绝对路径。例如,require('/home/marco/foo.js')
,加载的是/home/marco/foo.js
这个文件。
A module prefixed with './'
is relative to the file calling require()
.
That is, circle.js
must be in the same directory as foo.js
for
require('./circle')
to find it.
模块以'./'
为前缀,则路径是相对于调用require()
的文件。
也就是说,circle.js
必须和foo.js
在同一目录下,require('./circle')
才能找到。
Without a leading '/' or './' to indicate a file, the module is either a
"core module" or is loaded from a node_modules
folder.
当没有以'/'或者'./'来指向一个文件时,这个模块要么是"核心模块",要么就是从node_modules
文件夹加载的。
If the given path does not exist, require()
will throw an Error with its
code
property set to 'MODULE_NOT_FOUND'
.
如果指定的路径不存在,require()
会抛出一个code
属性为'MODULE_NOT_FOUND'
的错误。
从node_modules
文件夹中加载#
If the module identifier passed to require()
is not a native module,
and does not begin with '/'
, '../'
, or './'
, then node starts at the
parent directory of the current module, and adds /node_modules
, and
attempts to load the module from that location.
如果require()
中的模块名不是一个本地模块,也没有以'/'
, '../'
, 或是 './'
开头,那么node会从当前模块的父目录开始,尝试在它的/node_modules
文件夹里加载相应模块。
If it is not found there, then it moves to the parent directory, and so on, until the root of the tree is reached.
如果没有找到,那么就再向上移动到父目录,直到到达顶层目录位置。
For example, if the file at '/home/ry/projects/foo.js'
called
require('bar.js')
, then node would look in the following locations, in
this order:
例如,如果位于'/home/ry/projects/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
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
This allows programs to localize their dependencies, so that they do not clash.
这就要求程序员应尽量把依赖放在就近的位置,以防崩溃。
Folders as Modules#
It is convenient to organize programs and libraries into self-contained
directories, and then provide a single entry point to that library.
There are three ways in which a folder may be passed to require()
as
an argument.
可以把程序和库放到一个单独的文件夹里,并提供单一入口来指向它。有三种方法,使一个文件夹可以作为require()
的参数来加载。
The first is to create a package.json
file in the root of the folder,
which specifies a main
module. An example package.json file might
look like this:
首先是在文件夹的根目录创建一个叫做package.json
的文件,它需要指定一个main
模块。下面是一个package.json文件的示例。
{ "name" : "some-library",
"main" : "./lib/some-library.js" }
If this was in a folder at ./some-library
, then
require('./some-library')
would attempt to load
./some-library/lib/some-library.js
.
示例中这个文件,如果是放在./some-library
目录下面,那么require('./some-library')
就将会去加载./some-library/lib/some-library.js
。
This is the extent of Node's awareness of package.json files.
This is the extent of Node's awareness of package.json files.
If there is no package.json file present in the directory, then node
will attempt to load an index.js
or index.node
file out of that
directory. For example, if there was no package.json file in the above
example, then require('./some-library')
would attempt to load:
如果目录里没有package.json这个文件,那么node就会尝试去加载这个路径下的index.js
或者index.node
。例如,若上面例子中,没有package.json,那么require('./some-library')
就将尝试加载下面的文件:
./some-library/index.js
./some-library/index.node
./some-library/index.js
./some-library/index.node
Caching#
Modules are cached after the first time they are loaded. This means
(among other things) that every call to require('foo')
will get
exactly the same object returned, if it would resolve to the same file.
模块在第一次加载后会被缓存。这意味着(类似其他缓存)每次调用require('foo')
的时候都会返回同一个对象,当然,必须是每次都解析到同一个文件。
Multiple calls to require('foo')
may not cause the module code to be
executed multiple times. This is an important feature. With it,
"partially done" objects can be returned, thus allowing transitive
dependencies to be loaded even when they would cause cycles.
Multiple calls to require('foo')
may not cause the module code to be
executed multiple times. This is an important feature. With it,
"partially done" objects can be returned, thus allowing transitive
dependencies to be loaded even when they would cause cycles.
If you want to have a module execute code multiple times, then export a function, and call that function.
如果你希望一个模块多次执行,那么就输出一个函数,然后调用这个函数。
Module Caching Caveats#
Modules are cached based on their resolved filename. Since modules may
resolve to a different filename based on the location of the calling
module (loading from node_modules
folders), it is not a guarantee
that require('foo')
will always return the exact same object, if it
would resolve to different files.
模块的缓存是依赖于解析后的文件名。由于随着调用的位置不同,可能解析到不同的文件(比如需从node_modules
文件夹加载的情况),所以,如果解析到其他文件时,就不能保证require('foo')
总是会返回确切的同一对象。
The module
Object#
{Object}
{Object}
In each module, the module
free variable is a reference to the object
representing the current module. In particular
module.exports
is accessible via the exports
module-global.
module
isn't actually a global but rather local to each module.
在每一个模块中,变量 module
是一个代表当前模块的对象的引用。
特别地,module.exports
可以通过全局模块对象 exports
获取到。
module
不是事实上的全局对象,而更像是每个模块内部的。
module.exports#
Object
Object
The module.exports
object is created by the Module system. Sometimes this is not
acceptable, many want their module to be an instance of some class. To do this
assign the desired export object to module.exports
. For example suppose we
were making a module called a.js
module.exports
对象是通过模块系统产生的。有时候这是难以接受的,许多人想让他们的模块是某个类的实例。
因此,将要导出的对象赋值给 module.exports
。例如,假设我们有一个模块称之为 a.js
// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(function() {
module.exports.emit('ready');
}, 1000);
Then in another file we could do
那么,在另一个文件中我们可以这样写
var a = require('./a');
a.on('ready', function() {
console.log('module a is ready');
});
Note that assignment to module.exports
must be done immediately. It cannot be
done in any callbacks. This does not work:
Note that assignment to module.exports
must be done immediately. It cannot be
done in any callbacks. This does not work:
x.js:
x.js:
setTimeout(function() {
module.exports = { a: "hello" };
}, 0);
y.js:
y.js:
var x = require('./x');
console.log(x.a);
module.require(id)#
id
StringReturn: Object
module.exports
from the resolved moduleid
String- Return: Object 已解析模块的
module.exports
The module.require
method provides a way to load a module as if
require()
was called from the original module.
module.require
方法提供了一种像 require()
一样从最初的模块加载一个模块的方法。
Note that in order to do this, you must get a reference to the module
object. Since require()
returns the module.exports
, and the module
is
typically only available within a specific module's code, it must be
explicitly exported in order to be used.
注意,为了这样做,你必须取得一个对 module
对象的引用。
require()
返回 module.exports
,并且 module
是一个典型的只能在特定模块作用域内有效的变量,如果要使用它,就必须明确的导出。
module.id#
String
String
The identifier for the module. Typically this is the fully resolved filename.
用于区别模块的标识符。通常是完全解析后的文件名。
module.filename#
String
String
The fully resolved filename to the module.
模块完全解析后的文件名。
module.loaded#
Boolean
Boolean
Whether or not the module is done loading, or is in the process of loading.
不论该模块是否加载完毕,或者正在加载的过程中。
module.parent#
Module Object
Module Object
The module that required this one.
引入这个模块的模块。
module.children#
Array
Array
The module objects required by this one.
这个模块引入的所有模块对象。
总体来说...#
To get the exact filename that will be loaded when require()
is called, use
the require.resolve()
function.
为了获取调用 require
加载的确切的文件名,使用 require.resolve()
函数。
Putting together all of the above, here is the high-level algorithm in pseudocode of what require.resolve does:
综上所述,下面用伪代码的高级算法形式表达了 require.resolve 是如何工作的:
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS - 1
4. let DIRS = []
5. while I > ROOT,
a. if PARTS[I] = "node_modules" CONTINUE
c. DIR = path join(PARTS[0 .. I] + "node_modules")
b. DIRS = DIRS + DIR
c. let I = I - 1
6. return DIRS
从全局文件夹加载#
If the NODE_PATH
environment variable is set to a colon-delimited list
of absolute paths, then node will search those paths for modules if they
are not found elsewhere. (Note: On Windows, NODE_PATH
is delimited by
semicolons instead of colons.)
如果 NODE_PATH
环境变量设置为一个以冒号分割的绝对路径的列表,
找不到模块时 node 将会从这些路径中搜索模块。
(注意:在 windows 操作系统上,NODE_PATH
是以分号间隔的)
Additionally, node will search in the following locations:
此外,node 将会搜索以下地址:
- 1:
$HOME/.node_modules
- 2:
$HOME/.node_libraries
3:
$PREFIX/lib/node
1:
$HOME/.node_modules
- 2:
$HOME/.node_libraries
- 3:
$PREFIX/lib/node
Where $HOME
is the user's home directory, and $PREFIX
is node's
configured node_prefix
.
$HOME
是用户的主目录,$PREFIX
是 node 里配置的 node_prefix
。
These are mostly for historic reasons. You are highly encouraged to
place your dependencies locally in node_modules
folders. They will be
loaded faster, and more reliably.
这些大多是由于历史原因。强烈建议读者将所依赖的模块放到 node_modules
文件夹里。
这样加载的更快也更可靠。
访问主模块#
When a file is run directly from Node, require.main
is set to its
module
. That means that you can determine whether a file has been run
directly by testing
当 Node 直接运行一个文件时,require.main
就被设置为它的 module
。
也就是说你可以判断一个文件是否是直接被运行的
require.main === module
For a file foo.js
, this will be true
if run via node foo.js
, but
false
if run by require('./foo')
.
对于一个 foo.js
文件,如果通过 node foo.js
运行是 true
,但是通过 require('./foo')
运行却是 false
。
Because module
provides a filename
property (normally equivalent to
__filename
), the entry point of the current application can be obtained
by checking require.main.filename
.
因为 module
提供了一个 filename
属性(通常等于 __filename
),
所以当前程序的入口点可以通过 require.main.filename
来获取。
附录: 包管理技巧#
The semantics of Node's require()
function were designed to be general
enough to support a number of sane directory structures. Package manager
programs such as dpkg
, rpm
, and npm
will hopefully find it possible to
build native packages from Node modules without modification.
Node 的 require()
函数的语义被设计的足够通用化,以支持各种常规目录结构。
包管理程序如 dpkg,rpm 和 npm 将不用修改就能够从 Node 模块构建本地包。
Below we give a suggested directory structure that could work:
接下来我们将给你一个可行的目录结构建议:
Let's say that we wanted to have the folder at
/usr/lib/node/<some-package>/<some-version>
hold the contents of a
specific version of a package.
假设我们希望将一个包的指定版本放在 /usr/lib/node/<some-package>/<some-version>
目录中。
Packages can depend on one another. In order to install package foo
, you
may have to install a specific version of package bar
. The bar
package
may itself have dependencies, and in some cases, these dependencies may even
collide or form cycles.
包可以依赖于其他包。为了安装包 foo,可能需要安装包 bar 的一个指定版本。 包 bar 也可能有依赖关系,在某些情况下依赖关系可能发生冲突或者形成循环。
Since Node looks up the realpath
of any modules it loads (that is,
resolves symlinks), and then looks for their dependencies in the
node_modules
folders as described above, this situation is very simple to
resolve with the following architecture:
因为 Node 会查找它所加载的模块的真实路径(也就是说会解析符号链接), 然后按照上文描述的方式在 node_modules 目录中寻找依赖关系,这种情形跟以下体系结构非常相像:
/usr/lib/node/foo/1.2.3/
- Contents of thefoo
package, version 1.2.3./usr/lib/node/bar/4.3.2/
- Contents of thebar
package thatfoo
depends on./usr/lib/node/foo/1.2.3/node_modules/bar
- Symbolic link to/usr/lib/node/bar/4.3.2/
./usr/lib/node/bar/4.3.2/node_modules/*
- Symbolic links to the packages thatbar
depends on./usr/lib/node/foo/1.2.3/ - foo 包 1.2.3 版本的内容
- /usr/lib/node/bar/4.3.2/ - foo 包所依赖的 bar 包的内容
- /usr/lib/node/foo/1.2.3/node_modules/bar - 指向 /usr/lib/node/bar/4.3.2/ 的符号链接
- /usr/lib/node/bar/4.3.2/node_modules/* - 指向 bar 包所依赖的包的符号链接
Thus, even if a cycle is encountered, or if there are dependency conflicts, every module will be able to get a version of its dependency that it can use.
因此即便存在循环依赖或依赖冲突,每个模块还是可以获得他所依赖的包的一个可用版本。
When the code in the foo
package does require('bar')
, it will get the
version that is symlinked into /usr/lib/node/foo/1.2.3/node_modules/bar
.
Then, when the code in the bar
package calls require('quux')
, it'll get
the version that is symlinked into
/usr/lib/node/bar/4.3.2/node_modules/quux
.
当 foo 包中的代码调用 require('bar'),将获得符号链接 /usr/lib/node/foo/1.2.3/node_modules/bar
指向的版本。
然后,当 bar 包中的代码调用 require('queue')
,将会获得符号链接 /usr/lib/node/bar/4.3.2/node_modules/quux
指向的版本。
Furthermore, to make the module lookup process even more optimal, rather
than putting packages directly in /usr/lib/node
, we could put them in
/usr/lib/node_modules/<name>/<version>
. Then node will not bother
looking for missing dependencies in /usr/node_modules
or /node_modules
.
此外,为了进一步优化模块搜索过程,不要将包直接放在 /usr/lib/node
目录中,而是将它们放在 /usr/lib/node_modules/<name>/<version>
目录中。
这样在依赖的包找不到的情况下,就不会一直寻找 /usr/node_modules
目录或 /node_modules
目录了。
In order to make modules available to the node REPL, it might be useful to
also add the /usr/lib/node_modules
folder to the $NODE_PATH
environment
variable. Since the module lookups using node_modules
folders are all
relative, and based on the real path of the files making the calls to
require()
, the packages themselves can be anywhere.
为了使模块在 node 的 REPL 中可用,你可能需要将 /usr/lib/node_modules
目录加入到 $NODE_PATH
环境变量中。
由于在 node_modules 目录中搜索模块使用的是相对路径,基于调用 require()
的文件所在真实路径,因此包本身可以放在任何位置。