2023年4月17日发(作者:时事点评)nodejs的require的⽤法
require最常⽤的⽅法
require('http') 内淡泊名利的诗句
置模块
require('./rver') “./”表⽰当前路径,后⾯跟的是相对路径
require("../lib/rver") ../表⽰上⼀级⽬录,后⾯跟的也是相对路径
var http = require('http');
function start(){
rver = Server(function (req, res) {
eader(200, {"Content-Type": "text/plain"});
("Hello oschinan");
})
(8000);
("httpd start @8000");
}
= start;
//路径根据⾃⼰的实际情况⽽定
var rver = require("./learnNode/rver");
();
下⾯介绍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;
};
ference = 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() 时被载⼊的确切的⽂件名,使⽤ e() 函数。
综上所述,这是 e 的伪码描述:
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. Par 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] + "n书法英文
ode_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() 时基于⽂件的真实路径,因此软件包本⾝可以放在任何位置。