⚡️ Node.js v19,它来了!详解 6 大特性

阿轩的BUG
文章191
评论56
标签101
站点日志
作者总数:1位
置顶文章:0篇
标签总数:101条
文章总数:196篇
评论总数:56条
微语总数:201条
运行天数:2318天
最近更新:2026-07-28
文章标签
最新评论
Sherlock
2025-08-21
不是应该打包成apk文件吗,怎么突然就运行编译了,下一步呢
老金er
2025-05-25
人生设计非常必要,在信息化发达的今天,周围大部分人依然只能过着人生工程模式生活,长时间生活洗礼后,尽管“人生工程”已经不再适合很多人,他们也无法做出任何改变,人生设计给我们提供了新的思路,值得尝试
赏帮赚
2025-05-25
职场太多的尔虞我诈
三笑
2024-08-16
emlog6.0.1可以升级支持吗?
pony
2024-07-08
这篇文章提供了一种新的人生规划方法——"人生设计",它借鉴了产品设计的理念,鼓励人们以创造性和探索性的方式思考和规划自己的生活。以下是对这篇文章的几个评价维度: 创新性:将产品设计的理念应用于人生规划是一个新颖的视角,为人们提供了一种跳出传统生活轨迹,探索个性化生活路径的方法。 实用性:文章不仅提出了理念,还详细介绍了具体的实施步骤,包括自我评估、制定计划、原型设计和实践选择等,具有很强的操作性。 启发性:通过强调好奇心、不断尝试、重新定义问题等心态,文章鼓励人们打破常规,勇于探索未知,这对于激发个人潜能和创造力具有积极作用。 适应性:"人生设计"理念适用于不同人生阶段和不同背景的人,无论是希望从头开始的人,还是已经取得一定成就但希望探索新方向的人,都可以从中获得启发。 情感共鸣:文章对许多人对传统生活轨迹的不满和对改变的渴望进行了深刻的洞察,能够引起读者的共鸣。 可持续性:人生设计强调的是一个持续迭代和试错的过程,这与现实生活的发展规律相吻合,有助于人们在不断变化的环境中做出适应性调整。 教育意义:作为一种人生规划方法,"人生设计"可以作为教育的一部分,帮助年轻人更早地学会自我探索和规划,为未来的生活和职业发展打下基础。 局限性:尽管"人生设计"提供了一种新的思考框架,但它可能需要个人具备一定的自我认知和反思能力,对于一些缺乏自我探索经验的人来说,可能需要额外的指导和支持。 总体来说,这篇文章提供了一种有价值的人生规划方法,对于那些渴望改变、寻求个性化生活的人来说,是一种有益的参考和指导。
首页值得一看 🔍️

通译自:6 Major Features of Node.js 19. Details of Node.js 19 new features… | by Jennifer Fu | Oct, 2022 | Better Programming

Node 19 在 2022-10-18 发布。

我们知道 Node.js 版本分两种:LTS 和 Current

image.png

其中,Current 版本通常每 6 个月发布一次。

每年 4 月份发布新的偶数版本;

每年 10 月份发布新的奇数版本;

在刚过去的 10 月,发布的 V19.0.1 成为最新的 “Current” 尝鲜版,它一共带来 6 大特性。

1. HTTP(S)/1.1 KeepAlive 默认为 true

Node.js v19 设置 keepAlive 默认值为 true,这意味着所有出站的 HTTP(s) 连接都将使用 HTTP 1.1 keepAlive,默认时间为 5S;

代码测试:

const http = require('node:http');
console.log(http.globalAgent);
const https = require('node:https');
console.log(https.globalAgent);

我们可以对比看看 v16 和 v19 的 node server 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,
  scheduling: '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,
  scheduling: 'lifo',
  maxTotalSockets: Infinity,
  totalSocketCount: 0,
  maxCachedSessions: 100,
  _sessionCache: { map: {}, list: [] },
  [Symbol(kCapture)]: false
}

第 18、40 行,keepAlive 默认设置为 false;

V19

% 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,
    scheduling: 'lifo',
    timeout: 5000,
    noDelay: true,
    path: null
  },
  requests: [Object: null prototype] {},
  sockets: [Object: null prototype] {},
  freeSockets: [Object: null prototype] {},
  keepAliveMsecs: 1000,
  keepAlive: true,
  maxSockets: Infinity,
  maxFreeSockets: 256,
  scheduling: '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,
    scheduling: 'lifo',
    timeout: 5000,
    noDelay: true,
    path: null
  },
  requests: [Object: null prototype] {},
  sockets: [Object: null prototype] {},
  freeSockets: [Object: null prototype] {},
  keepAliveMsecs: 1000,
  keepAlive: true,
  maxSockets: Infinity,
  maxFreeSockets: 256,
  scheduling: 'lifo',
  maxTotalSockets: Infinity,
  totalSocketCount: 0,
  maxCachedSessions: 100,
  _sessionCache: { map: {}, list: [] },
  [Symbol(kCapture)]: false
}

第 14、16、42、44 行设置 keepAlive 默认值及时间;

启用 keepAlive 能使连接重用,提高网络的吞吐量。

另外,服务器将在调用 close() 自动断开空闲的客户端,内部依靠 http(s).Server.close API 实现;

这些修改,进一步优化了体验和性能。

2. 稳定的 WebCrypto API

WebCrypto API 是一个使用密码学构建的系统接口,在 node.js v19 趋于稳定(除 Ed25519、Ed448、X25519、X448 外)。

我们可以通过调用 globalThis.cryptorequire('node:crypto').webcrypto 来访问,下面以 subtle 加密函数为例;

const { subtle } = globalThis.crypto;

(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 加密;

最后创建 消息摘要,它是一种加密散列函数;

在控制台显示:key 、message 、digest 信息

% node server
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
}

3. 自定义 ESM resolution 调整

Node.js 已经删除 --experimental-specifier-resolution,其功能现在可以通过自定义加载器实现。

可以在这个库中测试:nodejs/loaders-test: Examples demonstrating the Node.js ECMAScript Modules Loaders API

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

将不会再报错,正常运行。

4. 移除对 DTrace/SystemTap/ETW 支持

在 Node.js v19中,移除了对 DTrace/SystemTap/ETW 的支持,主要是因为资源的优先级问题。

数据表明很少人用到 DTrace、SystemTap 或 ETW,维护它们没有多大的意义。

如果你想恢复使用,可提 issues => https://github.com/nodejs/node/issues/44550

5. 升级 V8 引擎至 10.7

Node.js v19 将 V8 JavaScript 引擎更新至 V8 10.7,其中包含一个新函数 Intl.NumberFormat,用于格式化敏感数字。

Intl.NumberFormat(locales, options)

对于不同的语言,传入不同的 locales:

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));

6. 试验 Node watch 模式

运行时增加了 node —watch 选项。

在 “watch” 模式下运行,当导入的文件被改变时,会重新启动进程。

比如:

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)。

推荐阅读:

上一篇
💬 谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64
下一篇
🩹 简单聊一聊 Vite 开发模式下的缓存策略