v11-10-nodejs 学习 - 三

Globals

queueMicrotask(callback)

v11 新增的 API。用于将 callback 加入到当前 phase 的 microtask 队列里。需要注意的是:process.nextTick 在 Nodejs 的每次循环每个 phase 中总是会比 microtask queue 优先执行

TextDecoder/TextEncoder

文本的编码、解码

URL/URLSearchParams

WHATWG 制定。下文应该会有相关介绍。


Inspector

可通过 Inspector 与 v8 的 Inspector 交互

1
const inspector = require('inspector');

Modules

缓存

默认下 nodejs 会对加载过的 module 进行缓存。但是,当操作系统为大小写不敏感(比如 MacOS)时,require (‘A.js’);require (‘a.js’); 会导致缓存两次。同时,不同代码处的 requre (‘a’) 可能返回不一样的模块,具体参考 nodejs 的模块加载机制。

require.main === module

可以用这个来判断当前文件是否是 nodejs 直接调用的文件。

循环引用

实际开发中很可能产生循环引用:a.js 引用了 b.js,b.js 也引用了 a.js。Nodejs 的处理方式是产生循环引用时,先返回一个未完成的 copy(这里是 a.js) 给调用者 (这里是 b.js),等待调用者加载完毕,再回过来加载调用者。

__dirname, __filename

分别表示当前文件的目录和当前文件绝对路径

exports 和 module.exports

exports 就是 module.exports 对象的引用。导出时具体有什么区别就跟 js 中一样了。可以把 exports 理解成函数的参数。它能保持对原对象的引用。

require.cache

返回一个对象,键值对是文件模块引用的其他模块。可以删除某个键值对 a,在下次 require (‘a’) 时会重新加载。

require.resolve(request[, options])

返回找到的文件模块的 path

require.resolve.paths(request)

返回找到的所有文件模块的 path


Net


Path

Path.resolve

如果首个参数不是绝对路径,那么会使用 process.cwd () (当前工作目录,就是启动 node 的目录)作为根路径。

Path.posix

返回一个包含平台相关的 path 对象。比如想在 Linux 上拼凑 windows 平台的路径。


perf_hooks


Process

process 对象,能提供当前 Nodejs 进程信息以及控制当前进程。

Process Events

process 对象也是 EventEmitter 的对象。有:

  • beforeExit
  • disconnect
  • exit
  • message
  • multipleResolves V10.12 新增 当一个 Promise 被多次 resolve 或者 reject 或者在 resolve 后 reject 或者反过来。该回调为错误捕获。
  • rejectionHandled
  • uncaughtException
  • unhandledRejection
  • warning
  • Signal Events

正确使用 uncaughtException 事件

该事件在触发后,进程会退出。应该在该回调中执行一些资源的清理(比如打开的文件)以及记录相关崩溃信息,而不要妄图去修复进城,期待它会再次好起来。详见官网关于 Warning: Using 'uncaughtException' correctly 一节。

process.exit()

会尽快退出进程,而不管是否还有其他异步回调等待完成。优雅的方式是使用 process.exitCode。

process.abort()

立即结束 Node.js 进程,生成一个核心文件。不能在 Worker threads 中调用。

process.allowedNodeEnvironmentFlags

V10.10 新增返回一个只读 Set,包含允许的 NODE_OPTIONS 环境变量。

process.chdir(directory)

更换当前目录

process.stderr

返回一个链接到 stderr(及 fd 为 2)的流。除非 fd 2 指向一个文件(这时是可写流),否则它都是一个 net.Socket(可读可写流)。

process.stdin

返回一个链接到 stdin(及 fd 为 0)的流。除非 fd 0 指向一个文件(这时是可读流),否则它都是一个 net.Socket(可读可写流)。

process.stdout

返回一个链接到 stdin(及 fd 为 1)的流。除非 fd 1 指向一个文件(这时是可写流),否则它都是一个 net.Socket(可读可写流)。

process.stdout and process.stderr 注意点

  1. 它们各自被 console.log 和 console.error 内部使用;
  2. 写操作可能是同步的,取决于流链接到的是什么,以及系统是 windows 还是 POSIX
    • 文件:在 windows 和 POSIX 上都是同步的
    • TTYs:windows 上异步,POSIX 上同步
    • 管道(以及 socket):windwos 上同步,POSIX 上异步

Stream


Trace Events


TTY

主要跟终端相关的操作。


V8

V8 模块包含内嵌在 NodejsV8 版本的二进制文件中的 API。由引用:

1
const v8 = require('v8');

v8.cachedDataVersionTag()

返回一个由 v8 版本、命令行标志和 CPU 特性决定的衍生值,为一个整数。主要用于判断 vm.Script cachedData buffer 是否与当前 nodejs 实例兼容。

v8.getHeapSpaceStatistics()

返回一个对象数组。代表了 V8 的堆空间的统计情况。

v8.getHeapStatistics()

返回堆统计。

v8.setFlagsFromString(flags)

编程设置 v8 的命令行 flag。使用起来得当心,VM 已经启动后再去修改设置,可能引起不可预估的行为,比如崩溃或者数据丢失,或者该设置无效。

Serialization API

处于实验阶段。

v8.serialize(value)

value 可为任意值。将 value 序列化为一个 buffer 对象。

v8.deserialize(buffer)

将 buffer 反序列化。buffer 可为 Buffer/TypedArray/DataView。

v8.Serializer

new Serializer()

实例序列。

serializer.writeHeader()

写入头信息,包含格式版本等。

serializer.writeValue(value)

写入值。

serializer.releaseBuffer()

返回 Buffer。返回内部存储的 buffer。当 buffer 被释放时,serializer 就不能再使用了。如果先前写入失败,调用该方法结果不可知。

serializer.transferArrayBuffer(id, arrayBuffer)

serializer.writeUint32 等

v8.Deserializer 略


VM

vm 模块提供 API 来编译 (javascript 本身是解释型语言,不需要传统意义的编译,此处的编译应该是转为可执行代码,理论上任何代码都需这一步) 代码及运行在 V8 虚拟机环境中。vm 不提供任何安全机制,不要使用它运行不可信的代码。
vm 提供了一个类似沙盒的容器,内部的环境与主程序环境隔离。可以传递给 vm 一个环境对象,这个对象的键值将作为 sandbox 的 global。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const vm = require('vm');
const x = 1;
const sandbox = { x: 2 };
vm.createContext(sandbox); // Contextify the sandbox.

const code = 'x += 40; var y = 17;';
// `x` and `y` are global variables in the sandboxed environment.
// Initially, x has the value 2 because that is the value of sandbox.x.
vm.runInContext(code, sandbox);

console.log(sandbox.x); // 42
console.log(sandbox.y); // 17

console.log(x); // 1; y is not defined.

Class: vm.Script

vm.Script 的实例包含了能直接在特定沙盒中运行的预编译代码。

Constructor: new vm.Script(code[, options])

  • code: 要预编译的代码
  • options: 对象或者字符串
    • filename: 用于 stack 追踪。默认’evalmachine.
    • lineOffset: 指定行数的偏移。默认 0
    • columnOffset
    • cachedData: ||
    • importModuleDynamically: 当 import () 被调用时回调。

script.createCachedData()

v10.6.0 增加
创建代码的缓存,可用于 Script 的构造器中 cachedData 选项。

script.runInContext(contextifiedSandbox[, options])

  • contextifiedSandbox: 一个通过 vm.createContext (context) 修改过的 context 对象
  • options:
    • displayErrors:
    • timeout: 超时时间。严格大于 0 的整数
    • breakOnSigint
  • Returns: 返回最后一条语句的结果

script.runInNewContext([sandbox[, options]])

  • sandbox: 将被 contextified 的对象。

script.runInThisContext([options])

运行在当前环境(主程序中)

Timer 等相关

由于内部机制,process.nextTick、microtask、Promise 等异步实现在 v8 和 nodejs 内,可能导致在某个环境中的代码逃离 timeout。如下:

1
2
3
4
5
6
7
8
9
10
11
const vm = require('vm');

function loop() {
while (1) console.log(Date.now());
}

vm.runInNewContext(
'Promise.resolve().then(loop);',
{ loop, console },
{ timeout: 5 }
);

即使设置了 timeout,程序也会被无限死循环打印 console.log,而不退出。(不存在是否有 vm 的参与,受 timer 的具体实现)。


Zlib


Worker Threads

当前为试验阶段。工作线程为 Nodejs 添加了线程级的 API。V10.5 以后版本,开启需要加–experimental-worker 选项。线程间通过 channel 通信。
Worker 线程类似于 HTML 规范中的 Worker,主要用于处理 CPU 密集型计算。不适合用作 IO 工作。
比起子进程、集群,worker 线程能共享内存。能通过传递 ArrayBuffer 实例或者 SharedArrayBuffer 实例来共享数据。

Worker.isMainThread

v10.5.0 新增,表示当前代码是否运行在 Worker 线程里。

Worker.parentPort

v10.5.0 新增,如果当前线程是 worker 线程,它指向父线程。

Worker.threadId

当前线程 ID。

省略

其它操作类似浏览器的 worker。比如发送数据、监听事件等。