NodeJs各版本新特性(持续更新)

摘要:

Node.js最新版本分为Current系列和LTS系列,两者分别面向不同需求场景:前者提供最新功能,后者强调长期稳定性。本文主要以偶数版本介绍。

更新时间:2025-06-19

v22(使用 22.16.0 测试)

概览

实验性功能变为稳定的功能:

新功能:

实验性功能:

开发者相对无感的底层更新:

监视模式(--watch)稳定化

新增于:(v18.11.0, v16.19.0),用于监视文件系统的变动,并自动重启。
v22.0.0 版本开始,这个指令成为稳定功能了。

要启用监视模式,只需要在启动 Node 应用时加上 --watch ****参数。例如:

bash 复制代码
node --watch index.js

关于 watch mode 详情请查看:(v18.11.0, v16.19.0)测试监听模式、(v18.11.0, v16.19.0)#监听模式

权限模型

v23.5.0v22.13.0 开始, 此功能不再处于实验阶段。开启命令从--experimental-permission修改为--permission

bash 复制代码
node --permission --allow-fs-read=./ index.js

关于权限模型详情请看:(v20.0.0 介绍)新的权限模型

WebSocket 客户端

从 v22.4.0 开始WebSocket属于稳定功能,不再需要 --experimental-websocket 来启用了。

如果需要关闭使用--no-experimental-websocket来禁用。

关于WebSocket客户端请查看(v21.0.0, v20.10.0):内置 WebSocket 客户端

import.meta

新增于:v21.2.0, v20.11.0,在 v22.16.0 标记为稳定。
关于 import.meta 属性请查看(v21.2.0, v20.11.0):import.meta.resolve

支持通过 require() 引入 ESM

js 复制代码
// CommonJS

// constant.mjs
export const str = 'hello world'

// test.mjs
import { str } from './constant.mjs'

export function output() {
  console.log(str)
}

// index.js
const { output } = require('./test.mjs')

output() // hello world

注意项:

  1. 最新版本已默认开启,若未开启可使用 -experimental-require-module 参数,如:node --experimental-require-module index.js
  2. 模块标记:确保 ESM 模块通过 package.json 中的 "type": "module" 或文件扩展名是 .mjs
  3. 完全同步:只有完全同步的 ESM 才能被 require() 导入,任何含有顶级 await 的 ESM 都不能使用这种方式加载。

运行 package.json 中的脚本

假设package.json有以下脚本:

json 复制代码
{
  "scripts": {
    "dev": "node index.js"
  }
}

以前我们都是通过 npm 来运行npm run dev,或者通过第三个包管理工具:pnpm devyarn dev等。

现在可以直接通过 node 运行,省略中间步骤,做到统一运行环境和提升性能。

bash 复制代码
➜ npm run dev

> node@1.0.0 dev
> node index.js

hello world

➜  node --run dev
hello world

增加流的默认高水位线

虽然 highWaterMark 是可配置的,但通常情况下,我们是使用默认值。在以前的版本里,highWaterMark 的默认值是 16k,Node 22 版本开始,默认值被提升到 64k 了。

js 复制代码
const fs = require('fs')

// 读取一个文件大小为:19433
const readStream = fs.createReadStream('test.md', {
  highWaterMark: 64 * 1024
})

readStream.on('data', (chunk) => {
  // 当highWaterMark:16 * 1024时,输出:Received chunk of size: 16384、Received chunk of size: 3049
  // 当highWaterMark:16 * 1024时,输出:Received chunk of size: 19433
  console.log(`Received chunk of size: ${chunk.length}`)
})

readStream.on('end', () => {
  console.log('End of file has been reached.')
})

highWaterMark 越大,缓冲区越大,占用内存越多,I/O 操作就减少,highWaterMark 越小,其他信息也对应相反。

文件模式匹配功能

fs.globfs.globSync

js 复制代码
const fs = require('fs')

fs.glob('./*.md', (err, files) => {
  if (err) {
    throw err
  }
  console.log(files) // ['./test.md']
})
const files = fs.globSync('./*.js')
console.log(files) // ['constant.js', 'index.js', 'test.js']

使用场景

  1. 自动化构建过程,如自动寻找和处理项目中的 JavaScript 文件。(比如 vue 路由放在指定目录,使用此方式自动导入。)
  2. 开发工具和脚本,需要对项目目录中的文件进行批量操作。
  3. 任何需要从大量文件中快速筛选出符合特定模式的文件集的应用。

ts 运行支持

Node.js v22.6.0 版本通过 --experimental-strip-types 标志,实现了对 TypeScript 的实验性支持。

这意味着开发者们现在可以在 Node.js 环境中直接执行 .ts 文件,而无需进行额外的编译步骤。

ts 复制代码
// index.ts
console.log('hello world')
bash 复制代码
node --experimental-strip-types index.ts // hello world!

V8 引擎升级至 12.4 版本

  • WebAssembly 垃圾回收:这一特性将改善 WebAssembly 在内存管理方面的能力。
  • Array.fromAsync:这个新方法允许从异步迭代器创建数组。
  • Set 方法和迭代器帮助程序:提供了更多内建的 Set 操作和迭代器操作的方法,增强了数据结构的操作性和灵活性。

Maglev 编译器默认启用

Maglev 是 V8 的新编译器,现在在支持的架构上默认启用。它主要针对短生命周期的命令行程序(CLI 程序)性能进行优化,通过改进 JIT(即时编译)的效率来提升性能。这对开发者编写的工具和脚本将带来明显的速度提升。

改进 AbortSignal 的创建性能

在这次更新中,Node 提高了 AbortSignal 实例的创建效率。AbortSignal 是用于中断正在进行的操作(如网络请求或任何长时间运行的异步任务)的一种机制。通过提升这一过程的效率,可以加快任何依赖这一功能的应用,如使用 fetch 进行 HTTP 请求或在测试运行器中处理中断的场景。

AbortSignal 的工作方式是通过 AbortController 实例来管理。AbortController 提供一个 signal 属性和一个 abort() 方法。signal 属性返回一个 AbortSignal 对象,可以传递给任何接受 AbortSignal 的 API(如 fetch)来监听取消事件。当调用 abort()方法时,与该控制器关联的所有操作将被取消。

js 复制代码
const controller = new AbortController()
const signal = controller.signal

fetch(url, { signal })
  .then((response) => response.json())
  .catch((err) => {
    if (err.name === 'AbortError') {
      console.log('请求取消')
    } else {
      console.error('请求错误:', err)
    }
  })

// 取消请求
controller.abort()

参考:

https://blog.csdn.net/jjc4261/article/details/139440329

https://nodejs.org/zh-cn/blog/release/v22.0.0

v20

概览

稳定的实验性功能:

实验性功能变动

新增的实验性功能:

其他变动及改进:

  • Web Crypto API 改进
  • ARM64 Windows 支持
  • HTTP/1.1 默认 Keep-Alive: 提高连接复用效率。
  • V8 引擎升级到 11.3
  • Web Assembly 系统接口(WASI)进展。
  • 性能优化
    1. EventTarget: 初始化成本减少 50%,加速相关子系统(如 fetch)。
    2. V8 Fast API: 用于优化 URL.canParse() 和定时器等 API 的性能。

新的权限模型

权限模型是一种在执行期间对特定资源限制访问的机制。要启用改机制,需要在 node 运行脚本时,添加--experimental-permission参数,启用该机制后,将限制对所有可用权限的访问。

bash 复制代码
node --permission index.js

此时执行脚本将会报以下错误:Error: Access to this API has been restricted

可以通过以下参数给指定文件或文件间授权:

bash 复制代码
--allow-fs-read=*  # 允许读取的文件
--allow-fs-write=* # 允许写入的文件

其中*可以是文件目录,文件路径或者是路径通配符,如以下:

bash 复制代码
# 仅允许入口脚本文件可读
node --experimental-permission --allow-fs-read=index.js index.js
# 当前目录下所有文件可读
node --experimental-permission --allow-fs-read=./ index.js
# 当前目录下,所有js文件可读
node --experimental-permission --allow-fs-read="./*.js" index.js
# 当前目录及同级test目录可读,多次使用--allow-fs-read参数
node --experimental-permission --allow-fs-read=./ --allow-fs-read=../test index.js

应用内检查是否有权限:permission.has(scope[, reference])

其中:scope可选值有:fs.writefs.readreference参数可选,不传则为当前目录,可以传递目录、文件地址、路径通配符。

js 复制代码
process.permission.has('fs.write') // 获取当前目录是否有写的权限
process.permission.has('fs.write', '../test') // 获取指定目录是否有写的权限
process.permission.has('fs.write', './*.js') // 获取指定路径通配符是否有写的权限

process.permission.has('fs.read') // 获取当前目录是否有读的权限
process.permission.has('fs.read', '/home/rafaelgss/protected-folder') // 获取指定目录是否有读的权限

其他权限扩展

  • 子进程权限:--allow-child-process
  • 多线程权限:--allow-worker
  • 原生插件权限:--allow-addons
  • WASI 权限:--allow-wasi

当使用权限控制的同时,也是有了上方的功能,就需要添加上方的参数以授权,若上方的功能内使用到了文件的读取或写入操作,也需要使用--allow-fs-read--allow-fs-write配置文件授权。

bash 复制代码
# 允许子进程权限
node --experimental-permission --allow-child-process --allow-fs-read=* process.js
# 其他相同
# ...

内置 WebSocket 客户端

在(v21.0.0, v20.10.0)版本添加,需要 --experimental-websocket 来启用。

除此之外,WebScoket 的实现还遵循了浏览器中 WebSocket API 的标准,这意味着在 Node 中使用 WebSocket 的方式将与在 JavaScript 中使用 WebSocket 的方式非常相似,有助于减少学习成本并提高代码的一致性。

注意:
这个是用于客户端的,如果创建服务端,还是推荐使用上面的三方库:wssocket.io

js 复制代码
// 无需导入,直接使用
const socket = new WebSocket('ws://localhost:8800')

socket.addEventListener('open', (event) => {
  socket.send('Hello Server!')
})
socket.addEventListener('error', (event) => {
  console.log('WebSocket error:', event)
})

测试模式稳定

从 v20.0.0 开始,Test Running标记为稳定。可以通过--test **启动。

bash 复制代码
node --test index.js

使用内置的 node:test 和 node:assert 模块,支持基本的测试用例编写、断言和报告生成。

js 复制代码
const { test } = require('node:test')
const assert = require('node:assert')
test('加法测试', () => {
  assert.strictEqual(1 + 1, 2)
})

关于Test Running详情请查看:(v18.11.0, v16.19.0)测试监听模式、(v18.1.0, v16.17.0)#测试模式

注意:不能和--watch-path, --check, --eval, --interactive同时使用

ESM Loader

自定义 ESM 加载器钩子在专用线程上运行,与主线程隔离。这为加载器提供了单独的作用域,并确保加载器和应用程序代码之间不会发生交叉污染。(官方建议使用--import来自定义钩子)

bash 复制代码
node --experimental-loader=./register-hooks.mjs ./index.js
node --import ./register-hooks.mjs ./index.js

示例:从 HTTPS 导入(注意:package.json里配置type: "module",或者文件后缀使用.mjs),这是 ESM 的加载器钩子。

js 复制代码
// index.js
import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js'
console.log(VERSION)

// https-hooks.mjs
import { get } from 'node:https'
export function load(url, context, nextLoad) {
  if (url.startsWith('https://')) {
    return new Promise((resolve, reject) => {
      get(url, (res) => {
        let data = ''
        res.setEncoding('utf8')
        res.on('data', (chunk) => (data += chunk))
        res.on('end', () =>
          resolve({
            format: 'module',
            shortCircuit: true,
            source: data
          })
        )
      }).on('error', (err) => reject(err))
    })
  }
  return nextLoad(url)
}

// 运行
node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./https-hooks.mjs"));' ./main.mjs

import.meta.resolve

在 ESM 中,import.meta.resolve() 现在同步返回模块路径,与浏览器行为一致。

其他 import.meta 属性:添加于:v21.2.0, v20.11.0

如果您习惯于 Node.js 的 CommonJS 模块,使用 **filename 和 **dirname 获取文件目录名和路径。那么在 ESM 中可以使用以下代码来替代。

js 复制代码
import.meta.dirname // 当前模块的绝对完整目录
import.meta.filename // 模块的完整绝对路径和文件名
import.meta.url // 模块的绝对url

url.parse()

替换了旧版 Ada 1.0.4,全面集成到 Node.js 中,用于解析 URL。优化了 url.parse() 和 url.domainToUnicode 等功能。性能显著提升,且不再依赖 ICU(国际化组件)进行主机名解析。

单执行应用程序

允许将 Node.js 应用打包为单个可执行文件,无需单独安装 Node.js 运行时。

bash 复制代码
# 创建应用配置文件,入口及出口
echo '{ "main": "hello.js", "output": "sea-prep.blob" }' > sea-config.json
# 生成blob文件
node --experimental-sea-config sea-config.json
# 创建副本,并根据需要改名
cp $(command -v node) hello  # 非win
node -e "require('fs').copyFileSync(process.execPath, 'hello.exe')" # win改名为后缀.exe
# 删除二进制文件的签名(仅mac和win)
codesign --remove-signature hello  # mac
signtool remove /s hello.exe # win
# 通过postject,将blob注入到复制的二进制文件中
npx postject hello NODE_SEA_BLOB sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 # linux
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 # win
npx postject hello NODE_SEA_BLOB sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 --macho-segment-name NODE_SEA # mac
# 签名二进制文件(仅mac和win)
codesign --sign - hello # mac
signtool sign /fd SHA256 hello.exe  # win
# 运行二进制文件
./hello world # 非win
./hello.exe world  # win

缺点:配置麻烦,使用到的静态资源需要在配置文件配置,并且对于比较大的项目使用会有各种问题,大项目还是建议使用别的工具,比较 ncc

环境变量文件配置

要加载 .env 文件,可以在启动 Node.js 应用时使用 --env-file CLI 标志。该标志指定要加载的 .env 文件路径。

bash 复制代码
# 单个文件
node --env-file=./.env ./index.js
# 多个文件,依次加载,后面的覆盖前面的
node --env-file=./.env --env-file=./.env.development ./index.js
js 复制代码
// 使用环境变量
console.log(process.env.PORT)

v18

实验性功能:

实验性功能稳定:

其他变动及改进:

  • Blob API:新增了 Blob API,封装了不可变的原始数据,可以在多个工作线程之间安全地共享这些数据。此外,新增的 BroadcastChannel 实例允许与绑定到同一 channel name 的所有其他 BroadcastChannel 实例进行异步一对多通信。
  • Web Streams API:Node.js 18 支持 Web Streams API,允许 JavaScript 以编程方式访问通过网络接收的数据流,提高了处理大数据的能力。
  • V8 引擎升级:V8 引擎升级到 10.1 版本,带来了新的数组方法如 findLast()和 findLastIndex(),提升了处理大量数据的能力
  • 性能优化:Node.js 18 在性能方面进行了优化,提升了代码执行速度和内存利用率,特别是在处理大量并发请求时表现更出色
  • 构建工具集成:与 Webpack 的集成更加紧密,实现了代码的压缩、合并、拆分等功能,提高了项目的构建效率和性能

测试监听模式

新增于:(v19.2.0, v18.13.0),在测试模式下,也可以使用监听模式了。

之前版本同时使用是会报错:

bash 复制代码
# node: either --test or --watch can be used, not both
node --test --watch index.js

之后版本就可以同时使用了。

关于 watch mode 详情请查看:(v18.11.0, v16.19.0)#监听模式
关于 test running 详情请查看:(v18.1.0, v16.17.0)#测试模式

fetch 不再需要--experimental-fetch

新增于:(v17.5.0, v16.15.0),用于在 node 中发起 HTTP 请求。
从 v18.0.0 不再需要使用--experimental-fetch,在 v21.0.0 标记为稳定

js 复制代码
const res = await fetch('https://nodejs.org/api/documentation.json')
if (res.ok) {
  const data = await res.json()
  console.log(data)
}

v16

实验性功能:

其他变动及改进:

  • V8 引擎升级 ‌:将 V8 升级至 9.0 版本,带来性能提升(如 Promise 和 Async/Await 的性能优化约 20%)。‌‌‌‌
  • 底层依赖升级 ‌:
    1. llhttp 升级至 6.0.0,优化 HTTP 报文解析性能。‌‌
    2. ICU(国际化组件)升级至 69.1 版本,增强国际化支持。‌‌
  • Web Crypto API 的试验性支持 ‌:提供加密功能接口(如签名、加密等),增强安全性。‌‌
  • AbortController 的稳定实现 ‌:允许开发者中断长时间运行的异步任务(如网络请求),提升资源利用率。

监听模式

新增于:(v18.11.0, v16.19.0),用于监视文件系统的变动,并自动重启。

要启用监视模式,只需要在启动 Node 应用时加上 --watch ****参数。例如:

bash 复制代码
node --watch index.js

这样不管是index.js发生改变,还是index.js依赖的文件发生改变,都会重新运行了。如果只需要监听文件改变重新运行,可以替代了nodemon包了。

注意:不能和--test同时使用

测试模式

新增于:(v18.1.0, v16.17.0),用于监视文件系统的变动,并自动重启。

要启用测试模式,只需要在启动 Node 应用时加上 --test ****参数。例如:

使用内置的 node:test 和 node:assert 模块,支持基本的测试用例编写、断言和报告生成。

js 复制代码
const { test } = require('node:test')
const assert = require('node:assert')
test('加法测试', () => {
  assert.strictEqual(1 + 1, 2)
})
bash 复制代码
node --test index.js

fetch

现代化的网络请求,替代 http 模块中的一些功能。

bash 复制代码
node --experimental-fetch index.js
js 复制代码
const res = await fetch('https://nodejs.org/api/documentation.json')
if (res.ok) {
  const data = await res.json()
  console.log(data)
}

promise 支持

  1. setTimeout 和 setInterval 被改造为返回 Promise 的形式,支持异步迭代器(如 for await),简化异步代码编写。‌‌‌‌
  2. AbortController API 的实现,用于中断异步操作(例如网络请求或文件读写)
js 复制代码
const { setTimeout, setInterval } = require('node:timers/promises')
setTimeout(2000).then(() => {
  console.log('123') // 123
})
setTimeout(2000, '345').then((res) => {
  console.log(res, '123') // 345, 123
})

评论

0条评论

logo

暂无内容,去看看其他的吧~