Node.js 20 已发布!快来看看 Node.js 20 的新功能吧

3,746 阅读3分钟

写在前面

Node.js 20 已经在 2023 年 4 月 18 日发布了,并且将于 2023 年 10 月进入长期支持(也就是 LTS 版本)。我们可以通过这里下载并体验:nodejs.org/en/download…

在 Node.js 20 中,有非常多的新变化和亮点,包括新的 Node.js 权限模型、同步的import.meta.resolve、稳定版的test_runner、升级到 11.3 版本的 V8 引擎等等。

性能提升

Node.js 20 运行时做了非常多的性能优化,主要包括URL模块、fetch()函数和EventTarget模块。

初始化EventTarget的开销减少了一半,所有依赖了这个模块的子系统都可以更快速的访问。

另外,还使用V8 Fast API(一个用于快速调用 C 函数的 API,详见这里)来提高 URL.canParse() 和计时器等 API 的性能。

同时,将Ada更新到了 2.0,这是一种用C++编写的性能极佳的 URL 解析器,用于获取更好的 URL 解析性能。

最后,开发团队也在通过重构的手段来优化streamURLURLSearchParams和字符串解码器的性能。

新变化&亮点功能

权限模型

Node.js 权限模型目前仍然是实验性的功能,用于在执行期间限制对特定资源的访问。具体包含以下功能:

  • 使用--allow-fs-read--allow-fs-write限制对文件读写系统的访问
  • 使用--allow-child-process限制访问 child_process
  • 使用--allow-worker限制访问 worker_threads
  • 使用--no-addons制对本机插件的访问

通过引入--allow-fs-read--allow-fs-write,Node.js 开发者可以更好地控制文件系统访问。这些实验性功能允许更精细地控制 Node.js 进程对于文件系统的访问。

要启用这些标志,开发人员可以使用--experimental-permission,并在后面加上所需的权限。例如,运行以下命令允许对整个文件系统进行读写访问:

$ node --experimental-permission --allow-fs-read=* --allow-fs-write=* index.js

此命令还支持通配符模式,例如,以下命令允许/home/目录中以test开头的所有文件和文件夹进行读取访问 test:

$ node --experimental-permission --allow-fs-read=/home/test* index.js

通配符模式也可用于允许一次访问多个文件或文件夹。例如,以下命令允许对/home/目录中以 开头的所有文件和文件夹进行读取访问 test:

$ node --experimental-permission --allow-fs-write=/tmp/ --allow-fs-read=/home/index.js index.js

启用权限模型后,可以使用 process.permission 来检查权限。

process.permission.has("fs.write"); // true
process.permission.has("fs.write", "/home/nodejs/protected-folder"); // true

详细文档:nodejs.org/api/permiss… 相关 PR:github.com/nodejs/node…

ESM loader 即将进入 stable 阶段

在 Node.js 中,我们可以通过ESM loader的生命周期钩子,也就是--experimental-loader=./foo.mjs这种形式来加载 ESM 模块。而现在 Node.js 20 支持了将加载模块放在与主线程隔离的专用线程中运行。这为加载模块提供了一个单独的作用域,并且确保了加载的模块和应用程序代码之间没有交叉污染。另外,为了与浏览器行为一致,import.meta.resolve() 现在默认为同步返回。

上述这些是ESM loader进入 stable 阶段之前的最后几项未完成的更改。当上述改动趋于稳定后,官方会将这些功能标记为 stable。这为 Node.js 应用更广泛地使用 ESM 打下了基础。

相关 PR:github.com/nodejs/node…

V8 引擎 11.3 版本

Node.js 20 中将 V8 引擎升级到了 11.3(是 Chromium 113 的一部分)。而新的引擎带来了如下新功能:

  • 支持 String.prototype.isWellFormedtoWellFormed
    • isWellFormed用于检查这个字符串是否是一个合法的 Unicode,而toWellFormed则会将一个字符串转换为 Unicode。
  • 提供了改变 Array 和 TypedArray 并返回改变后的数组的副本的函数。
    • 现有的Array.prototypeTypedArray.prototype的函数会直接修改接收的数组。而新函数会返回接收的数组的修改副本,并将原始数组保持不变。这些新函数在数据不可变的编程风格中很有用。
  • 可调整大小的 ArrayBuffer 和可增长的 SharedArrayBuffer。
  • 正则表达式支持v标志,并对+进行拓展。
    • 这个改动会将字符串的集合操作、字符串文字和 unicode 属性添加到正则表达式中。通过这些改动开发者可以用正则表达式匹配具有特定 unicode 字符的字符串。
    • 例如:使用/[\p{Script_Extensions=Greek}&&\p{Letter}]/v匹配所有希腊字母。
  • WebAssembly 尾调用。

相关 PR:github.com/nodejs/node…

Test Runner 模块已进入 stable 阶段

test_runner 模块在 Node.js 20 中已经进入了 stable 阶段,它主要用来编写并运行测试文件,包括:

  • describe/it/test函数,以及测试文件的钩子。
  • mock 数据。
  • 监听文件变化模式(watch mode)。
  • node --test支持并行运行多个测试文件。

举个使用test_runner的测试文件的例子:

import { test, mock } from "node:test";
import assert from "node:assert";
import fs from "node:fs";

mock.method(fs, "readFile", async () => "Hello ZY");
test("synchronous passing test", async (t) => {
  // This test passes because it does not throw an exception.
  assert.strictEqual(await fs.readFile("zy.txt"), "Hello ZY");
});

相关 PR:github.com/nodejs/node…

准备单一可执行应用时需要传入 blob

单一可执行应用 (Single Executable Applications, SEA)是指无需依赖 Node.js 环境,可以直接在操作系统中执行的程序。一般开发者会选择pkgboxednode等社区方案来讲一个 Node.js 应用打包成一个可执行文件。Node.js 在 2022 年成立了相关团队,负责提供官方的 SEA 生成方案。截止到目前,SEA 相关的功能依旧是实验性的功能。

在 Node.js 20 中,构建单一可执行应用现在需要从 JSON 配置中注入由 Node.js 准备的 blob,而不是注入原始 JS 文件,这项改动是为了允许将多个共享资源嵌入到 SEA 中。

举个例子:

sea-config.json

{
  "main": "hello.js",
  "output": "sea-prep.blob"
}

这会将 blob 写入文件 sea-prep.blob

$ node --experimental-sea-config sea-config.json

这样,就可以将此 blob 注入到二进制文件中了。

相关 PR:github.com/nodejs/node…

Web Crypto API

在 Node.js 20 中,将 Web Crypto API 的各个函数参数按照 WebIDL 的标准进行了修改,使之与浏览器等其它 Web Crypto API 实现对齐。这进一步提高了 Node.js 的 Web Crypto API 与其他实现的互操作性。

相关 PR:github.com/nodejs/node…

支持 ARM64 Windows

Node.js 支持非常多的平台和架构,开发者们希望它可以在任何环境下运行。而一个好消息是,Node.js 20 现在支持在 ARM64 Windows 环境下运行了!

相关 PR:github.com/nodejs/node…

WASI(Web Assembly System Interface)的新进展

虽然在 Node.js 中,WASI 相关功能依旧是实验性的,但在 Node.js 20 中,我们已经不再需要使用命令行选项来启用 WASI。另外就是在new WASI()实例化 WASI 对象时,需要默认传入一个version参数来明确它所对应的版本。

升级 Node.js

Node.js 14 将于 2023 年 4 月结束它的生命周期,Node.js 16 (LTS) 也将于 2023 年 9 月结束生命周期。

因此是时候开始考虑将 Node.js 升级到 Node.js 18 (LTS) 或 Node.js 20(即将成为 LTS)了!