版本说明
这两个版本有什么区别呢?Node.js 21 适合在特定环境下进行早期功能测试,而 Node.js 20 LTS 则适用于生产部署。Node.js 21 将在未来 6 个月内成为“当前”版本,直到 2024 年 4 月。以下是完整的 Node.js 发布计划。
Node.js 的发布可以分为三个阶段,奇数版本号的发布线路不会被提升为 LTS 版本,也就不会经历“Active LTS”和“Maintenance”阶段。
- Current(当前):包含大部分进入 nodejs/node 主分支的非主要(非破坏性)变更。
- Active LTS(活跃长期支持):新功能、错误修复和经LTS团队审核后被确定适合该发布线路且稳定的更新。
- Maintenance(维护):关键错误修复和安全更新。新功能可能会根据LTS团队的判断加入。通常只在新功能支持迁移到后续发布线路的情况下才会添加。
如果你想要尝试最新的Node.js功能,那么 Node.js 21 是个很好的测试平台,它提供了即将到来的新特性的先期体验。Node.js 的发布计划特别关注这一点。但是如果正在准备或已经在生产环境中使用 Node.js,则应该选择较稳定的版本,如Node.js 20 和 18 LTS。这些版本可以保证可靠性和稳定性,并且会在较长时间内得到支持和维护。
Node.js 21 的亮点包括将 V8 JavaScript 引擎升级到 11.8 版本,稳定的WebStreams和 fetch功能,一个用于更改模块默认值的新实验性标志(--experimental-default-type),对测试运行器的许多更新,内置 WebSocket 客户端等!
主要更新
稳定的WebStreams和 fetch功能
Node.js 21 对fetch模块和WebStreams进行了重要更新,并将它们标记为稳定版本。
这一变化影响到了WebStreams、FormData、Headers、Request、Response和fetch等模块。
内置 WebSocket 客户端
这个版本新增了一个实验性的浏览器兼容的 WebSocket 实现,可以通过使用参数--experimental-websocket来开启。但是,像所有实验性功能一样,它可能会随时发生变化。
V8 11.8
按照惯例,Node.js 21 中包含了新版本的 V8 引擎(更新到版本11.8,该版本是 Chromium 118 的一部分),带来了性能的改进和新的语言功能,包括:
- 数组分组
- ArrayBuffer.prototype.transfer
- 扩展的 WebAssembly 常量表达式
Node.js 测试运行器支持通配符
在 Node.js 21 中,测试运行器引入了对通配符表达式的支持。通配符是一种模式语法,可以用来匹配多个文件路径。在测试过程中,可以使用通配符表达式来指定要运行的测试文件。
通过使用通配符表达式,可以更方便地选择和执行特定类型的测试文件,而不需要一个个地指定它们的路径。例如,如果想运行所有具有.test.js文件扩展名的文件,无论这些文件位于哪个目录下,可以使用类似于node --test **/*.test.js的命令。这样,测试运行器会自动匹配并执行符合该模式的测试文件。
ESM:支持改变模块默认值
experimental-default-type 是 Node.js 的一个实验性特性,可以用来切换默认的模块系统。这意味着开发者可以使用不同的模块类型,并在需要时进行切换,使得 Node.js 应用更加灵活,能够应对不同的场景。
标志 --experimental-default-type=module 用于将模块类型切换成 ES 模块。对于已经明确定义为 ES 模块或 CommonJS 的代码,例如在 package.json "type" 字段中或文件扩展名为 .mjs/.cjs 或 --input-type 标志等,不会受到影响。在使用 --experimental-default-type=module 标志时,原本默认解析为 CommonJS 的代码将被解析成 ES 模块。
此外,Node.js 团队还在探索使用检测 ES 模块语法作为Node.js识别文件是否为ES模块的一种方式,目标是最终找到一种支持ES模块语法的方法,并尽可能减少变更。
模块自定义钩子 globalPreload 已被移除,改用 register 和 initialize
模块自定义钩子 globalPreload 已被移除。取而代之的是,使用 register 方法将数据从应用线程发送到自定义钩子,并使用 initialize 钩子在线程之间建立通信通道。
fs.writeFile 函数添加 flush 选项
在写入文件时,有可能数据并不会立即刷新到永久存储中。这可能导致后续读取操作看到旧的数据。该版本为 fs.writeFile 系列函数添加了一个 flush 选项,该选项可以在成功写入操作结束时强制刷新数据到永久存储。
性能
性能是一个运行时的重要属性,@nodejs/performance 团队在过去一年中一直努力改进 URL、fetch、streams、node:fs 和 HTTP 等方面的性能。
Streams
Node.js 流团队不断优化可写流和可读流。在这个版本中,通过移除冗余检查、利用位图以及以更高效的方式安排回调来进一步优化流操作。
HTTP
在此之前,当向分块响应写入数据时,无论响应是否处于 corked 状态,Node.js 都会为每个 .write(...)调用创建一个单独的数据块。这会在客户端和服务端都产生不必要的开销。
该更新通过在取消 corked 状态时,为所有 write(...) 调用创建一个单一的数据块来解决了这一问题。
考虑以下基于 Transfer-Encoding 文档的示例:
res.cork();
res.write('Mozilla');
res.write(' Developer Network');
res.uncork();
在每个数据块的开头,您需要以十六进制格式添加当前数据块的长度,然后跟着 '\r\n',再接着是数据块本身,最后再加上另一个 '\r\n'。终止块是正常的数据块,唯一的例外是它的长度为零。
最终生成的响应流为:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
7\r\n
Mozilla\r\n
18\r\n
Developer Network\r\n
0\r\n
\r\n
在 Node.js 21 中,当取消 corked 状态时,所有数据块都会合并成一个单独的数据块,从而减少了很多不必要的开销。
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
25\r\n
Mozilla Developer Network\r\n
0\r\n
\r\n
llhttp 9.1.2 强制严格模式执行
- 在以前的 Node.js 版本中,默认情况下未启用严格模式。在 Node.js 21 中,强制执行了以前包含在严格模式中的所有设置,提高了代码的可靠性和安全性。
- 现在,标头后面必须有 \r\n(之前允许单独使用 \r)。此外,数据块后必须有 \r\n,以确保一致的数据处理。
- 在解析带有 Connection: close 标头的消息后不再允许传输数据。这一变化增强了协议遵从性并改善了连接处理。
为适应特定的用例,引入了--insecure-http-parser 标志。该选项允许用户禁用上述更改,并保持与以前的解析行为的向后兼容性。
这些更新旨在增强整个系统的稳定性,并改善 Node.js 应用的数据处理一致性。鼓励开发人员审查其代码库并相应地调整其实现,以确保与最新版本的无缝集成。
navigator 对象集成
在 Node.js 21 中,引入了全局 navigator 对象,增强了 Web 的互操作性。现在,可以通过 navigator.hardwareConcurrency 访问硬件并发信息。