Node.js v10.1.0 Documentation
Modules
Stable
在 Node.js 模块系统中,每个文件都会被当做一个独立的模块。假设有一个名为 foo.js
:
const circle = require('./circle.js');
console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);
第一行中,foo.js
加载了同文件夹下的模块circle.js
.
·circle.js`中的内容:
const { PI } = Math;
exports.area = (r) => PI * r ** 2;
exports.circumference = (r) => 2 * PI * r;
模块circle.js
暴露了arear()
和circumfence()
方法。方法和对象通过对这个特殊的exports
对象赋额外的属性值添加到了模块的根中。
模块的本地变量将是私有的,因为模块被Node.js封装在一个函数中。在本例中,变量PI
对circle.js
是私有的。
module.exports
属性可以赋值一个新值(例如函数或对象)
下面,bar.js
使用的是square
模块,它导出一个Square
类。
const Square = require('./square.js');
const mySquare = new Square(2);
console.log(`The area of mySquare is ${mySquare.area()}`);
square
模块是在square.js
中定义的
// assigning to exports will not modify module, must use module.exports
module.exports = class Square {
constructor(width) {
this.width = width;
}
area() {
return this.width ** 2;
}
};
模块系统是在require('module')
模块中实现的。
访问 main module
node.js直接运行的文件,require.main
会被设置为这个文件的module. 由此,可以通过 require.main == module
判断当前文件是否被node.js直接运行 (via node *.js
)。
因为module
提供了一个filename
属性(通常情况下等于__filename
)。当前应用的入口可以通过require.main.filename
获取到。
require 方法的实现
当调用 require()
方法时, 使用 require.resolve()
方法获取到准确的文件名称,逻辑如下:
require(X) from module at path Y
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with '/'
a. set Y to be the filesystem root
3. If X begins with './' or '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. THROW "not found"
LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.json is a file, parse X.json to a JavaScript Object. STOP
4. If X.node is a file, load X.node as binary addon. STOP
LOAD_INDEX(X)
1. If X/index.js is a file, load X/index.js as JavaScript text. STOP
2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
3. If X/index.node is a file, load X/index.node as binary addon. STOP
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. let M = X + (json main field)
c. LOAD_AS_FILE(M)
d. LOAD_INDEX(M)
2. LOAD_INDEX(X)
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 I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
a. if PARTS[I] = "node_modules" CONTINUE
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIRS + DIR
d. let I = I - 1
5. return DIRS
Caching
modules 当第一次被加载时放到cache中。也就是说每次调用 require('foo')
时,如果解析到同一个文件,将会得到同一返回对象。
如果想要让一个module多次执行代码,export 一个 function, 然后调用那个 function
Module Caching 警告
module基于他们被解析的文件名加载到cache中。由于module可能因为调用module的路径不同而被resolve不同的文件名,所以并不保证每次调用同一个 require(module)
都会返回同一个对象。
对于大小写敏感的文件系统或者操作系统,即使module被解析为同一个文件,但是因为大小写的原因,module还是会多次加载。
Core Modules
Node.js 有一些module被编译为二进制文件,这些module在 Node.js 源文件中定义,位于lib/
目录下面。
Core Module 一直被预加载在cache中。require('http')
将会调用内置的 HTTP module,即使当前目录下面有个名为 http 的文件
Cycles
a.js
:
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js
:
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js
:
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
output
:
$ 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
为了防止无穷循环,一个 a.js
unfinished copy 会返回给 b.js
File Modules
如果没有找到指定名称的问价,Node.js 会尝试添加文件后缀名 .js
,.json
,.node
都没有找到会返回 MODULE_NOT_FOUND
Folders as Modules
推荐把 programs 和 libraries 组织进一个目录下, 并提供一个统一的入口。有三种方式可以把文件夹的名字作为 require()
方法的参数传送。
- 在文件夹根目录下创建一个
package.json
的文件,并指定main
mudule。
{
"name" : "some-library",
"main" : "./lib/some-library.js"
}
- 创建一个
index.js
的文件作为入口 - 创建一个
index.node
的文件作为入口
Loading from node_modules
Folders
如果给 require()
传递的 module 名称不是一个 core module, 并且没有以 '/'
,'../'
,'./'
作为开始, 那么Node.js 会尝试从 node_modules
目录下面查找所需要的module。
举例来说:有一个位于 ''/home/ry/projects/foo.js'' 调用 require('bar.js')
, node.js 回按照下面的方式顺序查找 bar.js
- /home/ry/projects/node_modules/bar.js
- /home/ry/node_modules/bar.js
- /home/node_modules/bar.js
- /node_modules/bar.js
此外,可以使用已知路径的 module 作为参考,去查找相对于这个 module 的 其他 module;
Loading from the global folders
如果在 node_modules
里仍然没有找到指定的module,Node.js 会搜索系统环境变量 NODE_PATH
指定的目录。当然,前提是设置了这个环境变量。
墙裂推荐把相关 module 放在 node_modules
目录下面,这样加载会更快更稳定。
The module wrapper
当一个module里面的代码被执行之前,Node.js 会先把module里面的代码封装起来:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
这样做的优点是:
- 会把变量限定在这个module里面,而不是global对象下面。
- 提供一些貌似global的对象。(
export
,'require,'module','__filename
,'__dirname`)
The module scope
__dirname (type:string)
Example: 运行node example.js
from /Users/mjr
console.log(__dirname);
// Prints: /Users/mjr
console.log(path.dirname(__filename));
// Prints: /Users/mjr
__filename(type:string)
Example: 运行node example.js
from /Users/mjr
console.log(__filename);
// Prints: /Users/mjr/example.js
console.log(__dirname);
// Prints: /Users/mjr
给定两个文件a.js 和 b.js , a.js 依赖 b.js, 将会有如下的结构
- /Users/mjr/app/a.js
- /Users/mjr/app/node_modules/b/b.js
exports
等同于 module.exoports
module (type:object)
当前module
require() (type:function)
用于调用依赖module
require.cache(type:object)
所有通过require方法调用过的依赖都存储于这个对象当中。如果删除了对象中的某个Key,下一次调用 require()
方法时会重新加载这个module。但是这个方法不适用 native addons.
require.extensions(弃用)
require.main(type:object)
代表程序启动时的入口module.
require.resolve(request[这个是参数])
使用 require
的机制去查找某个 module 的路径,但是只返回解析到的 filename, 而且不加载这个module.
require.resolve.paths(request[这个也是参数])
返回查找某个module遍历的路径信息(type:string[] | )
如果是core module, 返回 null
The module
Object
module.children
:当前module所有的依赖项
module.exports
:可以用来赋值某个类的实例(exports 不可以)
a.js
:
const EventEmitter = require('events');
module.exports = new EventEmitter();
// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(() => {
module.exports.emit('ready');
}, 1000);
b.js
:
const a = require('./a');
a.on('ready', () => {
console.log('module "a" is ready');
});
赋值操作需要马上完成,不可以在会掉中完成。下面的代码是不会有效的:
x.js
:
setTimeout(() => {
module.exports = { a: 'hello' };
}, 0);
y.js
:
const x = require('./x');
console.log(x.a);
其他属性
module.filename
:<string> 全文件名
module.id
:<string> module 标识 通常是全文件名
module.loaded
:<boolean> module是否已加载
module.parent
:<module> 第一个调用这个module 的 module
module.paths
:<string[]> 搜索路径
module.require(id)
:module外调用require的方法
Node.js v10.1.0 Documentation的更多相关文章
- Node.js v7.4.0 Documentation Addons
https://nodejs.org/docs/latest/api/addons.html Node.js Addons are dynamically-linked shared objects, ...
- node.js 在 Express4.0 框架使用 Connect-Busboy 实现文件上传
node.js下四种post提交数据的方式 今天说分享的是其中一种,就是上传文件. Express 4.0 以后,将功能原子化,高内聚,低耦合,独立出了很多中间件 今天主要分享文件上传 对于conne ...
- npm dose not support Node.js v10.15.3
事件起因: 楼主在vue-cli官网,尝试使用vue-cli3脚手架+yarn包管理器构建项目时,命令行窗口提示node版本不对.如下图 这个大家都知道该如何去解决,直接去node官网下载符合版本的n ...
- Node.js & module system
Node.js & module system Node.js v10.9.0 Documentation https://nodejs.org/api/modules.html#module ...
- 《Node.js核心技术教程》学习笔记
<Node.js核心技术教程>TOC \o "1-3" \h \z \u 1.章模块化编程 2019.2.19 13:30' PAGEREF _101 \h 1 08D ...
- Node.js 多线程完全指南
[原文] 很多人都想知道单线程的 Node.js 怎么能与多线程后端竞争.考虑到其所谓的单线程特性,许多大公司选择 Node 作为其后端似乎违反直觉.要想知道原因,必须理解其单线程的真正含义. Jav ...
- 性能追击:万字长文30+图揭秘8大主流服务器程序线程模型 | Node.js,Apache,Nginx,Netty,Redis,Tomcat,MySQL,Zuul
本文为<高性能网络编程游记>的第六篇"性能追击:万字长文30+图揭秘8大主流服务器程序线程模型". 最近拍的照片比较少,不知道配什么图好,于是自己画了一个,凑合着用,让 ...
- Node.js 0.12: 正确发送HTTP POST请求
Node.js 0.12: 正确发送HTTP POST请求 本文针对版本:Node.js 0.12.4 之前写过一篇Node.js发送和接收HTTP的GET请求的文章,今天再写一篇,讲发送POST的请 ...
- 玩儿转物联网IoT - 在Beagle Bone Black上运行node.js 程序
物联网(IoT)技术方兴未艾,智能手环,智能血压计,智能眼镜甚至智能鞋垫都开始进入我们的生活,各种智能设备层出不穷,世界已经到了一个"人有多大胆,地有多大产"的时代,不玩儿点物联网 ...
随机推荐
- ActiveMQ学习总结(3)——spring整合ActiveMQ
1.参考文献 Spring集成ActiveMQ配置 Spring JMS异步发收消息 ActiveMQ 2.环境 在前面的一篇ActiveMQ入门实例中我们实现了消息的异步传送,这篇博文将如何在spr ...
- 洛谷 P1553 数字反转(升级版)
P1553 数字反转(升级版) 题目描述 给定一个数,请将该数各个位上数字反转得到一个新数. 这次与NOIp2011普及组第一题不同的是:这个数可以是小数,分数,百分数,整数.整数反转是将所有数位对调 ...
- [AngularFire] Angular File Uploads to Firebase Storage with Angular control value accessor
The upload class will be used in the service layer. Notice it has a constructor for file attribute, ...
- 生成CPU使用率 sin 曲线 控制cpu使用率 编程之美
入职Oracle 以后想着把之前写过的<编程之美>中控制CPU使用率曲线的程序再写一边, 可是总是由于入职须要学习的东西太多, 没有时间. 程序早就写好了. 最终有机会贴出来了.o(∩∩) ...
- Flume的Events
Flume NG传输的数据的基本单位是event,如果是文本文件,通常是一行记录,这也是事务的基本单位.
- 通过NFS、FTP、HTTP三种方法安装Redhat Linux (高清版)
本节教程讲述了通过在Red Hat Linux服务器端假设NSF Server来进行Linux系统安装的过程,并详细介绍了如何制作网络启动盘的细节.演示直观,讲解通俗易懂,特别适合初学者学 ...
- 不用浏览器,直接用代码发送文件给webservices所在服务器 并且可以周期行的发送
package com.toic.test; import java.io.DataInputStream; import java.io.DataOutputStream; import java. ...
- BZOJ2434: [Noi2011]阿狸的打字机(fail树+dfs序)
Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...
- python运算符优先级表
运算符 描述 lambda Lambda表达式 or 布尔“或” and 布尔“与” not x 布尔“非” in,not in 成员测试 is,is not 同一性测试 <,<=,> ...
- 【Uva 11080】Place the Guards
[Link]: [Description] 一些城市,之间有道路相连,现在要安放警卫,警卫能看守到当前点周围的边,一条边只能有一个警卫看守,问是否有方案,如果有最少放几个警卫. [Solution] ...