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封装在一个函数中。在本例中,变量PIcircle.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的文件作为入口

源链接
未完待续

猜你喜欢

转载自www.cnblogs.com/ArvinZhao/p/9067051.html