NodeV19问世?看看它带来了什么新变化?
大家好,很高兴又见面了,我是"web 前端分享",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发! 1.理解Node发版规律1.1 什么Semver?
Sem+ver, Sem是Semantic(语义的)之意,ver是Version(版本)之意。整体表示一种版本命名的方式,要体现一定的版本变更内容的含义。目前的Semver一般指由Semver.org组织制定的版本规范。其基本要求如下:版本号的基本形式为MAJOR.MINOR.PATCH 3部分组成,每个部分的含义如下:MAJOR: 软件的API改变MINOR: 修改或添加功能,但保持向后兼容(API未变)PATCH:补丁,主要是错误修复
Semver的含义1.2 LTS(Long Term Support)与Current含义?
关于Node.js的发布流程,有以下几个要点:每6个月发布一个主要版本(即Major版本),作为Current版本。注意:它可能是奇数版本也可能是偶数版本。但是,因为其是最新的,所以包含Node.js平台的最新特性4月发布偶数版本,10月发布奇数版本每12个月将一个版本转入LTS版本,LTS代表了一个被不断修正与改进的版本。LTS版本要经历两个阶段:活跃期(Active)与维护期(Maintenance)活跃期共18个月,即在不改变兼容性的情况下,周期性修改Bug并合并其他版本的重要修改(1)每个时刻Current版本只有一个,LTS版本可能有3个,LTS-Active版本可能有2个。在Node.js官网中给出的LTS版本总是处于LTS的最新版本
(2)该版本处于活跃期(Ative)时,可以看到其MINOR版本在不断升级维护期共12个月,只负责修改本版本的Bug以及特别紧急问题的修复,如安全性问题
下面是Node官网的最新信息,即最新Current版本V19.2.0、而LTS版本为V18.12.1版。
Node 19最新版本发布2.Node v19+带来那些特性?2.1 HTTP(S)/1.1 KeepAlive 默认为 true
Node.js v19 将 keepAlive 的默认值设置为 true,这意味着所有 HTTP(s) 连接将默认启动 HTTP/1.1的keepAlive,默认时间为 5S。 const http = require("node:http"); // http链接 console.log(http.globalAgent); const https = require("node:https"); // https链接 console.log(https.globalAgent);
我们可以对比下 v16 和 v19 的节点服务器 Agent 配置差异,首先切换到 V16 版本: nvm use 16 //now using node v16.0.0 (npm v7.10.0) node server
输入信息如下: agent { _events: [ Object: null prototype] { free: [ function (anonymous)], newListener: [ Function: maybeEnableKeylog] }, _eventsCount: 2, _maxListeners: undefined, defaultPort: 80, protocol: "http:", options: [ Object: null prototype] { path: null }, requests: [ Object: null prototype] {}, sockets: [ Object: null prototype] {}, freeSockets: [ Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: Infinity, maxFreeSockets: 256, schedule: "lifo", maxTotalSockets: Infinity, totalSocketCount: 0, [ Symbol(kCapture)] : false } agent { _events: [ Object: null prototype] { free: [ function (anonymous)], newListener: [ Function: maybeEnableKeylog] }, _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: "https:", options: [ Object: null prototype] { path: null }, requests: [ Object: null prototype] {}, sockets: [ Object: null prototype] {}, freeSockets: [ Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: Infinity, maxFreeSockets: 256, schedule: "lifo", maxTotalSockets: Infinity, totalSocketCount: 0, maxCachedSessions: 100, _sessionCache: { map: {}, list: [] }, [ Symbol(kCapture)] : false }
第 5、37 行,keepAlive 默认值设置为 false。接着请看下面的 V19 输出,首先切换到 19 版本: nvm use 19 //now using node v19.0.0 (npm v8.19.2) node server
输出信息如下: agent { _events: [ Object: null prototype] { free: [ function (anonymous)], newListener: [ Function: maybeEnableKeylog] }, _eventsCount: 2, _maxListeners: undefined, defaultPort: 80, protocol: "http:", options: [ Object: null prototype] { keepAlive: true, schedule: "lifo", timeout: 5000, noDelay: true, path: null }, requests: [ Object: null prototype] {}, sockets: [ Object: null prototype] {}, freeSockets: [ Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: true, // 这里是true maxSockets: Infinity, maxFreeSockets: 256, schedule: "lifo", maxTotalSockets: Infinity, totalSocketCount: 0, [ Symbol(kCapture)] : false } agent { _events: [ Object: null prototype] { free: [ function (anonymous)], newListener: [ Function: maybeEnableKeylog] }, _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: "https:", options: [ Object: null prototype] { keepAlive: true, schedule: "lifo", timeout: 5000, noDelay: true, path: null }, requests: [ Object: null prototype] {}, sockets: [ Object: null prototype] {}, freeSockets: [ Object: null prototype] {}, keepAliveMsecs: 1000, keepAlive: true, // 这里是true maxSockets: Infinity, maxFreeSockets: 256, schedule: "lifo", maxTotalSockets: Infinity, totalSocketCount: 0, maxCachedSessions: 100, _sessionCache: { map: {}, list: [] }, [ Symbol(kCapture)] : false }
第 21、50将keepAlive设置为true,启用 keepAlive 可实现连接重用并提高网络吞吐量。此外,服务端会调用 close() 自动断开空闲客户端,内部依赖于 http(s).Server.close API 实现,这些修改将进一步优化 Node 体验和性能。这个改动有以下几个注意点: http.globalAgent 和 https.globalAgent 默认都使用 keep-alive Agent 代理会解析、应用从 server 处获取到的 Keep-Alive 头部(如果其值小于 Agent 的超时时间) http(s).Server.close 现在在内部调用 closeIdleConnections 方法 2.2 稳定的 WebCrypto API
WebCrypto API 是使用密码学构建的系统接口,在 node.js v19(Ed25519、Ed448、X25519、X448 除外)中趋于稳定。可以通过调用 globalThis.crypto 或者 require("node:crypto").webcrypto 来访问,比如下面的代码; const { subtle } = globalThis.crypto; // 或者require("node:crypto").webcrypto (async function () { const key = await subtle.generateKey( { name: "HMAC", hash: "SHA-256", length: 256, }, true, ["sign", "verify"] ); console.log("key=", key); const enc = new TextEncoder(); const message = enc.encode("I love cupcakes"); console.log("message=", message); const digest = await subtle.sign( { name: "HMAC", }, key, message ); console.log("digest=", digest); })();
我们对上面的代码做一个简单的说明,一共包括三个步骤: 首先生成 HMAC 密钥,可同时用于验证消息数据的完整性和真实性; 然后,加密字符串"I love cupcakes" 最后创建消息摘要,这是一个加密哈希函数;
执行如下命令: node server
此时控制台显示 key、message、digest 等信息: // 执行命令 key = CryptoKey { type: "secret", extractable: true, algorithm: { name: "HMAC", length: 256, hash: [Object] }, usages: [ "sign", "verify" ] } message = Uint8Array( 15) [ 73, 32, 108, 111, 118, 101, 32, 99, 117, 112, 99, 97, 107, 101, 115] digest = ArrayBuffer { [Uint8Contents]: < 30 01 7a 5c d9 e2 82 55 6b 55 90 4f 1d de 36 d7 89 dd fb fb 1a 9e a0 cc 5d d8 49 13 38 2f d1 bc>, byteLength: 32 } 2.3 自定义 ESM 解析调整
Node.js 已删除 --experimental-specifier-resolution 能力 ,其功能现在可通过自定义加载器使用(可以在文末参考文献链接中尝试)。 git clone https://github.com/nodejs/loaders-test.git % cd loaders-test/commonjs-extension-resolution-loader % yarn install
例如 loaders-test/commonjs-extension-resolution-loader/test/basic-fixtures/index.js 文档: import { version } from "process"; import { valueInFile } from "./file"; import { valueInFolderIndex } from "./folder"; console.log(valueInFile); console.log(valueInFolderIndex);
./file 如果没有自定义加载器,则不会搜索文件的扩展名,比如./file.js 或者./file.mjs。而通过设置自定义加载器后,可以解决以上问题: import { isBuiltin } from "node:module"; import { dirname } from "node:path"; import { cwd } from "node:process"; import { fileURLToPath, pathToFileURL } from "node:url"; import { promisify } from "node:util"; import resolveCallback from "resolve/async.js"; const resolveAsync = promisify(resolveCallback); const baseURL = pathToFileURL(cwd() + "/").href; export async function resolve(specifier, context, next) { const { parentURL = baseURL } = context; if (isBuiltin(specifier)) { return next(specifier, context); } // `resolveAsync` works with paths, not URLs if (specifier.startsWith("file://")) { specifier = fileURLToPath(specifier); } const parentPath = fileURLToPath(parentURL); let url; try { const resolution = await resolveAsync(specifier, { basedir: dirname(parentPath), // For whatever reason, --experimental-specifier-resolution=node doesn"t search for .mjs extensions // but it does search for index.mjs files within directories extensions: [".js", ".json", ".node", ".mjs"], }); url = pathToFileURL(resolution).href; } catch (error) { if (error.code === "MODULE_NOT_FOUND") { // Match Node"s error code error.code = "ERR_MODULE_NOT_FOUND"; } throw error; } return next(url, context); }
测试命令如下: % node --loader=./loader.js test/basic-fixtures/index (node: 56149) ExperimentalWarning: Custom ESM Loaders is an experimental feature. This feature could change at any time (Use `node --trace-warnings ...` to show where the warning was created) hello from file.js
此时程序不会再报错,能正常运行。 2.4. 移除对 DTrace/SystemTap/ETW 的支持
在 Node.js v19 中,移除了对 DTrace/SystemTap/ETW 的支持,主要是因为资源优先级的问题。数据显示,很少有人使用 DTrace、SystemTap 或 ETW,因此维护它们没有多大意义(如果有问题,可以在文末提供的链接中提交 issue)。 2.5 升级 V8 JavaScript引擎到 V10.7
Node.js v19 将 V8 JavaScript 引擎更新为 V8 10.7(这也是 Chromium 107 默认的 JavaScript 引擎),其中包括一个用于格式化敏感数字的新函数 Intl.NumberFormat。 Intl.NumberFormat(locales, options);
对于不同的语言,传入不同的语言环境: const number = 123456.789; console.log( new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format( number ) ); console.log( new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" }).format( number ) ); console.log( new Intl.NumberFormat("ar-SA", { style: "currency", currency: "EGP" }).format( number ) ); console.log( new Intl.NumberFormat("zh-CN", { style: "currency", currency: "CNY" }).format( number ) ); Intl.NumberFormat v3 API 是一个新的 TC39 ECMA402 stage 3 提案,扩展了预先存在的 Intl.NumberFormat。
除了对 NumberFormat 的扩展,Node V19 还包括了如下变更: Node.js 19 附带了 llhttp@8.1.0 Node.js 19 更新了 npm@8.19.2 2.6 尝试使用 Node watch
当导入的文件发生更改时,以"watch"模式运行的程序会重新启动,此功能已经在 v19.0.0 和 v18.11.0+ 中可用。 // server.js const express = require("express"); const path = require("path"); const app = express(); app.use(express.static(path.join(__dirname, "../build"))); app.listen(8080, () => console.log("Express server is running on localhost:8080") );
启动命令如下: node --watch server
输出内容如下: (node: 67643) ExperimentalWarning: Watch mode is an experimental feature. This feature could change at any time (Use `node --trace-warnings ...` to show where the warning was created) Express server is running on localhost: 8080
Node.js 14 将于 2023 年 4 月结束更新维护,Node.js 16(LTS)预计将于 2023 年 9 月结束更新维护。建议大家开始计划按需升级到 Node.js 16 (LTS) 或 Node.js 18 (LTS),更多说明可以阅读文末资料。 参考资料
https://github.com/nodejs/loaders-test
https://github.com/nodejs/node/issues/44550
https://nodejs.org/en/blog/announcements/v19-release-announce/#node-watch-experimental
https://github.com/nodejs/node/pull/43522
https://github.com/nodejs/node/pull/44859
https://baijiahao.baidu.com/s?id=1626332802026818591&wfr=spider&for=pc