require的用法

时间:2024-11-16 18:46:04

require最常用的方法

require(‘http’) 内置模块

require(‘./server’) “./”表示当前路径,后面跟的是相对路径

require(“../lib/server”) ../表示上一级目录,后面跟的也是相对路径

var http = require('http'); 
function start(){ 
    server = (function (req, res) {   
          (200, {"Content-Type": "text/plain"});   
          ("Hello oschina\n");   
    })   
    (8000);   
    ("httpd start @8000");   
} 
 = start;   

//路径根据自己的实际情况而定  
var server = require("./learnNode/server"); 
(); 

下面介绍require
模块

Node 使用 CommonJS 模块系统。

Node 有一个简单的模块加载系统。在 Node 中,文件和模块一一对应。比如,在 加载同一目录中的 模块。

的内容:

var circle = require(‘./’);
( ‘The area of a circle of radius 4 is ’
+ (4));

的内容:

var PI = ;

= function (r) {
return PI * r * r;
};

= function (r) {
return 2 * PI * r;
};

模块 导出了 area() 函数和 circumference() 函数,这样它们就能从模块外部访问了。要导出对象,将其添加到特殊的 exports 对象就行。

模块的局部变量是私有的。在本例中,变量 PI 是 私有的。
核心模块

Node 有一些已编译成二进制的模块,这些模块将在本文档的其他地方详细​​介绍。

核心模块在 Node 源代码的 lib/ 文件夹中定义。

使用 require() 时,核心模块总是优先加载。例如,require(‘http’) 总是返回内置的 HTTP 模块,即使该名称的文件存在。
文件模块

如果没有找到确切的文件,Node 将尝试给所需的文件名​​添加 .js 后缀再加载,然后再尝试 .node。

.js 文件被视为 JavaScript 文本文件,而 .node 文件被视为已编译的插件模块,用 dlopen 加载。

模块以 ‘/’ 开头表示使用文件的绝对路径。例如,require(‘/home/marco/’) 将加载 /home/marco/ 文件。

模块以 ‘./’ 开头表示调用 require() 时使用相对路径。也就是说,为了保证 require(‘./circle’) 能找到, 必须和 在同一目录。

如果不以 ‘/’ 或’./’ 开头,该模块可以是一个“核心模块”,也可是一个从 node_modules 文件夹中加载的模块。
node_modules 文件夹中加载

如果传递给 require() 有模块标识符是不是原生模块,而且不以 ‘/’、’../’ 或’./’ 开头,那么 Node 从当前模块的父目录+/node_modules 这个位置尝试加载。

如果还是没有找到,那么它跳到上层目录并依此类推,直到找到模块,或者达到根目录为止。

例如,如果在文件 ‘/home/ry/projects/’ 中调用 require(‘’),那么 Node 将在下列位置查找,顺序如下:

/home/ry/projects/node_modules/
/home/ry/node_modules/
/home/node_modules/
/node_modules/

这就允许程序将依赖关系本地化,防止它们冲突。
优化 node_modules 查找过程

当嵌套依赖关系的层次很深时,这个文件查找列表可能会变得很长。因此,在查找时进行如下优化:

首先,/node_modules 不会附加到一个以 /node_modules 结尾的文件夹后面。

其次,如果调用 require() 的文件已经在一个 node_modules 层级里,那么最顶层的 node_modules 文件夹将被视为搜索树的根。

例如,如果在文件 ‘/home/ry/projects/foo/node_modules/bar/node_modules/baz/’ 中调用 require(‘’),那么 Node 将搜索下列位置:

/home/ry/projects/foo/node_modules/bar/node_modules/baz/node_modules/
/home/ry/projects/foo/node_modules/bar/node_modules/
/home/ry/projects/foo/node_modules/

以文件夹作为模块

Node 允许用户在独立的目录中方便地组织程序,然后提供单一入口指向该库。有三种方式可以将文件夹作为 require() 的参数。

第一种方式是在该文件夹中创建 文件,指定一个 main 模块。一个典型的 文件可能看起来像这样:

{ “name” : “some-library”,
“main” : “./lib/” }

如果此文件位于 ./some-library 文件夹,则 require(‘./some-library’) 会尝试加载 ./some-library/lib/。

这是 Node 能找到 文件的情况。

如果在该目录中没有 文件,那么 Node 将尝试加载该目录中的 或 文件。例如,如果上面的例子找不到 ,那么 require(‘./some-library’) 将试图加载:

./some-library/
./some-library/

缓存

模块在首次被加载后会缓存起来。这意味着每次调用 require(‘foo’) 将得到完全相同的对象,如果它被解析为同一个文件的话。
总结……

为了得到调用 require() 时被载入的确切的文件名,使用 () 函数。

综上所述,这是 的伪码描述:

require(X)
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with ./ or /,
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW “not found”

LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If is a file, load as JavaScript text. STOP
3. If is a file, load as binary addon. STOP

LOAD_AS_DIRECTORY(X)
1. If X/ is a file,
a. Parse X/, and look for “main” field.
b. let M = X + (json main field)
c. LOAD_AS_FILE(M)
2. LOAD_AS_FILE(X/index)

LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)

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
6. return DIRS

加载

在 Node 中, 是一个字符串数组,表示模块不以 ‘/’ ‘./’ 或 ‘..’ 打头的搜索路径。例如,如果 设置为:

[ ‘/home/micheil/.node_modules’,
‘/usr/local/lib/node_modules’ ]

则调用 require(‘bar/’) 会搜索以下位置:

1: '/home/micheil/.node_modules/bar/'
2: '/usr/local/lib/node_modules/bar/'

可以在运行时修改 数组来改变这种行为。

它的值最初从 NODE_PATH 环境变量而来,那是一个冒号分隔的绝对路径列表。在前面的例子中,NODE_PATH 环境变量可能被设置为:

/home/micheil/.node_modules:/usr/local/lib/node_modules

只有使用上面的 node_modules 算法找不到模块时才会尝试 。全局模块的优先级低于捆绑依赖。
注意 请不要修改

出于兼容性的考虑, 仍然是模块查找过程的首选策略。尽管如此,它可能会在将来的版本中废弃。

虽然它看起来似乎是个好主意,但在实践中一个可变的 列表往往是麻烦和混乱的根源。
修改 毫无用处

这行代码并不会像期望的那样:

= [ ‘/usr/lib/node’ ];

它的结果就是丢弃了 Node 实际的模块查找路径引用,并创建了一个毫无用处的指向别处的新的引用。
中加入相对路径……不是个好主意

如果你这样做:

(‘./lib’);

它不会添加 ./lib 在文件系统上已解析的完整路径。相反,它实际增加的是 ‘./lib’,这意味着如果你在 /a/b/ 中 require(‘’),那么它会查找 /a/b/lib/。如果你之后又在 /l/m/n/o/ 中 require(‘’),那么它就会查找 /l/m/n/o/lib/。

在实践中,人们往往将它作为捆绑依赖的临时解决办法,这个技巧是不太稳妥的。
零隔离

有一种糟糕的设计:所有模块共用一个 数组。

结果,如果一个 Node 程序依赖于这种行为,它可能会永久而微妙地改变同一进程中其它 Node 程序的行为。当应用程序的复杂度增加时,我们倾向于封装功能,这些行为很难预料的部分会成为开发者的恶梦。
增编:软件包管理小贴示

在 Node 中,require() 函数的语义被设计成通用性足以支持大量合理的目录结构。因此 dpkg、rpm 和 npm 之类的包管理器可以从 Node 模块构建原生包而不作更改。

下面我们给出一个可以工作的建议的目录结构:

比方说,我们希望 /usr/lib/node// 文件夹中包含某个包的特定版本的内容。

一个软件包可以依赖别的包。为了安装 foo 包,你可能需要安装 bar 包的特定版本 。可能该 bar 包本身有依赖关系,在某些情况下,这些依赖关系甚至可能发生冲突或者形成回路。

由于 Node 在加载任何模块时都会查找它的真实路径(即:会解析符号链接),然后在 node_modules 文件夹用上文描述的方式查找依赖。使用以下架构可以很简单地解决:

/usr/lib/node/foo/1.2.3/ -foo包的内容,版本1.2.3。
/usr/lib/node/bar/4.3.2/ -bar 包的内容,foo依赖这个包。
/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 所依赖的包的符号链接。

因此,即使遇到一个回路,或者有依赖冲突,每个模块都能够得到它依赖的可用版本。

当 foo 包中有代码 require(‘bar’) 时,它会得到符号链接至 /usr/lib/node/foo/1.2.3/node_modules/bar 的版本。然后,当 bar 包调用 require(‘quux’) 时,它会得到符号链接至 /usr/lib/node/bar/4.3.2/node_modules/quux 的版本。

此外,为了使模块查找过程更加优化,而​​不是直接把包放到 /usr/lib/node 中,我们可以它们放到 /usr/lib/node_modules// 里。这样,Node 就不用在 /usr/node_modules 或 /node_modules 中查找了。

为了使 REPL 能够正常引用模块,可以将 /usr/lib/node_modules 添加至 $NODE_PATH环境变量。因为使用 node_modules 文件夹查找模块时的路径都是相对的,而且调用 require() 时基于文件的真实路径,因此软件包本身可以放在任何位置。