写在前面
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 解析性能。
最后,开发团队也在通过重构的手段来优化stream
、URL
、URLSearchParams
和字符串解码器的性能。
新变化&亮点功能
权限模型
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.isWellFormed
和toWellFormed
。isWellFormed
用于检查这个字符串是否是一个合法的 Unicode,而toWellFormed
则会将一个字符串转换为 Unicode。
- 提供了改变 Array 和 TypedArray 并返回改变后的数组的副本的函数。
- 现有的
Array.prototype
和TypedArray.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 环境,可以直接在操作系统中执行的程序。一般开发者会选择pkg
、boxednode
等社区方案来讲一个 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)了!