Node.js 常用知识点归纳

一、模块

http://nodejs.cn/api/modules.html

1. 模块概念

在 Node.js 模块系统中,每个文件都被视为一个独立的模块。 例如,假设有一个名为 foo.js 的文件:

const circle = require('./circle.js');
console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`);

在第一行中, foo.js 加载了与 foo.js 在同一目录中的 circle.js 模块。

以下是 circle.js 的内容:

const { PI } = Math;

exports.area = (r) => PI * r ** 2;

exports.circumference = (r) => 2 * PI * r;

circle.js 模块导出了 area() 和 circumference() 函数。通过在特殊的 exports 对象上指定额外的属性,可以将函数和对象添加到模块的根部。

2. 模块加载

  • Node.js 的 require() 函数的语义被设计得足够通用化,可以支持许多合理的目录结构。
  • require() 总是会优先加载核心模块。 例如, require('http') 始终返回内置的 HTTP 模块,即使有同名文件。

2.1. 文件模块加载

如果按确切的文件名没有找到模块,则 Node.js 会尝试带上 .js、 .json等拓展名再加载。

以 '/' 为前缀的模块是文件的绝对路径。 例如, require('/home/marco/foo.js') 会加载 /home/marco/foo.js 文件。

以 './' 为前缀的模块是相对于调用 require() 函数所在文件的相对路径。 

当没有以 '/'、 './' 或 '../' 开头来表示文件时,这个模块必须是一个核心模块或加载自 node_modules 目录。

2.2. 目录模块加载

可以把程序和库放到一个单独的目录,然后提供一个单一的入口来指向它。 

把目录递给 require() 作为一个参数,有三种方式。

第一种方式是在根目录下创建一个 package.json 文件,并指定一个 main 模块。 例子, package.json 文件类似:

{ 
  "name" : "some-library",
  "main" : "./lib/some-library.js" 
}

如果这是在 ./some-library 目录中,则 require('./some-library') 会试图加载 ./some-library/lib/some-library.js

这就是 Node.js 处理 package.json 文件的方式。

如果目录里没有 package.json 文件,则 Node.js 就会试图加载目录下的 index.js 或 index.node 文件。 例如,如果上面的例子中没有 package.json 文件,则 require('./some-library') 会试图加载:

  • ./some-library/index.js
  • ./some-library/index.node

2.3. node_modules 目录加载

如果传递给 require() 的模块标识符不是一个核心模块,也没有以 '/' 、 '../' 或 './' 开头,则 Node.js 会从当前模块的父目录开始,尝试从它的 /node_modules 目录里加载模块。 如果还是没有找到,则移动到再上一层父目录,直到文件系统的根目录。

例子,如果在 '/home/ry/projects/foo.js' 文件里调用了 require('bar.js'),则 Node.js 会按以下顺序查找:

  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

3. 模块作用域

3.1. __dirname

当前模块的目录名。 与 __filename 的 path.dirname() 相同。

示例,从 /Users/mjr 运行 node example.js

console.log(__dirname);
// 打印: /Users/mjr
console.log(path.dirname(__filename));
// 打印: /Users/mjr

3.2. __filename

当前模块的文件名。 这是当前的模块文件的绝对路径。

示例:从 /Users/mjr 运行 node example.js

console.log(__filename);
// 打印: /Users/mjr/example.js
console.log(__dirname);
// 打印: /Users/mjr

3.3. exports

这是一个对于 module.exports 的更简短的引用形式。

3.4. module

对当前模块的引用。 module.exports 用于指定一个模块所导出的内容,即可以通过 require() 访问的内容。

3.5. require()

用于引入模块、 JSON、或本地文件。 可以从 node_modules 引入模块。 可以使用相对路径(例如 ./、 ./foo、 ./bar/baz、 ../foo)引入本地模块或 JSON 文件,路径会根据 __dirname 定义的目录名或当前工作目录进行处理。

// 引入本地模块:
const myLocalModule = require('./path/myLocalModule');

// 引入 JSON 文件:
const jsonData = require('./path/filename.json');

// 引入 node_modules 模块或 Node.js 内置模块:
const crypto = require('crypto');

3.6. require.resolve(request)

  • request: <string> 待解析的模块路径(相对路径)
  • returns: <string>   解析后的模块路径(绝对路径)

使用内部的 require() 机制查询模块的位置(绝对路径), 此操作只返回解析后的文件名,不会加载该模块。

示例:在 Node.js 中使用 fs 读取文件的时候,经常碰到要拼一个文件的绝对路径的问题 (fs 处理相对路径均以进程执行目录为准)。

之前一直的方法都是,使用 path 模块以及 __dirname 变量 。

fs.readFileSync(path.join(__dirname, './assets/file.txt'));

使用 require.resolve 可以简化这一过程

fs.readFileSync(require.resolve('./assets/file.txt'));

此外, require.resolve 还会在拼接好路径之后检查该路径是否存在, 如果 resolve 的目标路径不存在, 就会抛出 Cannot find module './file.txt' 的异常, 省略了一道检查文件是否存在的工序 (fs.exists).

4. module 对象

4.1. module.exports

module.exports 对象由 Module 系统创建。导出对象需要将对象赋值给 module.exports

例如,假设正在创建一个名为 a.js 的模块:

const EventEmitter = require('events');

module.exports = new EventEmitter();

// 处理一些工作,并在一段时间后从模块自身触发 'ready' 事件。
setTimeout(() => {
  module.exports.emit('ready');
}, 1000);

然后,在另一个文件中可以这么做:

const a = require('./a');
a.on('ready', () => {
  console.log('模块 a 已准备好');
});

4.2. exports

这是一个对于 module.exports 的更简短的引用形式。module.exports.f = ... 可以更简洁地写成 exports.f = ...

二、path(路径)

path 模块提供用于处理文件路径和目录路径的实用工具。 它可以使用以下方式访问:

const path = require('path');

2.1. path.dirname(path)

path.dirname() 方法返回 path 的目录名。

path.dirname('/foo/bar/baz/asdf/quux');
// 返回: '/foo/bar/baz/asdf'

2.2. path.join([...paths])

path.join() 方法使用平台特定的分隔符将所有给定的 path 片段连接在一起。

零长度的 path 片段会被忽略。 如果连接的路径字符串是零长度的字符串,则返回 '.',表示当前工作目录。

path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'

path.join('foo', {}, 'bar');
// 抛出 'TypeError: Path must be a string. Received {}'

2.3. path.resolve([...paths])

path.resolve() 方法将路径或路径片段的序列解析为绝对路径

每个参数都类似在当前目录执行一个cd操作,从左到右执行,返回的是最后的当前目录(pwd)!

  1. 如果在处理完所有给定的 path 片段之后还未生成绝对路径,则再加上当前工作目录。
  2. 生成的路径需要删除尾部斜杠。
  3. 零长度的 path 片段会被忽略。
  4. 如果没有传入 path 片段,则 path.resolve() 将返回当前工作目录的绝对路径。
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'

path.resolve('/foo/bar', '/tmp/file/');
// 返回: '/tmp/file'

path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// 如果当前工作目录是 /home/myself/node,
// 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'

参考:小tips:path的join和resolve的使用区别

三、process(进程)

process 对象是一个全局变量,它提供有关当前 Node.js 进程的信息并对其进行控制。 作为一个全局变量,它始终可供 Node.js 应用程序使用,无需使用 require()

3.1. process.env

process.env 属性返回包含用户环境的对象。

process.env.foo = 'bar';
console.log(process.env.foo);
// => bar
原文地址:https://www.cnblogs.com/codestarer/p/13635521.html