Node V19+问世?看看它带来了什么新变化?

大家好,很高兴又见面了,我是"web 前端分享",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

1.理解Node发版规律

1.1 什么Semver?

Sem+ver, Sem是Semantic(语义的)之意,ver是Version(版本)之意。整体表示一种版本命名的方式,要体现一定的版本变更内容的含义。目前的Semver一般指由Semver.org组织制定的版本规范。其基本要求如下:版本号的基本形式为MAJOR.MINOR.PATCH 3部分组成,每个部分的含义如下:

Semver的含义

1.2 LTS(Long Term Support)与Current含义?

关于Node.js的发布流程,有以下几个要点:

(1)每个时刻Current版本只有一个,LTS版本可能有3个,LTS-Active版本可能有2个。在Node.js官网中给出的LTS版本总是处于LTS的最新版本

(2)该版本处于活跃期(Ative)时,可以看到其MINOR版本在不断升级

下面是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 体验和性能。这个改动有以下几个注意点:

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

我们对上面的代码做一个简单的说明,一共包括三个步骤:

执行如下命令:

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 还包括了如下变更:

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

展开阅读全文

页面更新:2024-05-05

标签:奇数   偶数   含义   加载   活跃   命令   版本   链接   引擎   最新

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top