Node.js 26中悄然取代多年临时解决方案的新功能。
Node.js 26带来了多项新功能,取代了旧的解决方案:用于处理日期的Temporal API、原生TypeScript执行环境、内置的缓存辅助工具,以及一些其他小改进。
1. 我们终于可以不再假装 Date 是一个真正的日期 API 了
以下是一些非常普通的 JavaScript 代码:
const date = new Date("2026-09-08");
console.log(date);
现在试着回答一个稍难一些的问题:
在纽约召开的会议的本地日期是什么?
或者:
在这个账单日期的基础上加上三个月。
又或者:
日历日期与精确时间点之间到底有什么区别?
就在这时,Date 开始暴露出问题。
这正是 Temporal 如此重要的原因。
Node.js 26 默认启用了 Temporal API,终于为 JavaScript 提供了用于表示瞬间、日历日期、持续时间以及时区的独立概念。
不必再这样编写:
const date = new Date();
现在你可以这样写:
const today = Temporal.Now.plainDateISO();
const invoiceDate =
Temporal.PlainDate.from("2026-09-08");
const dueDate =
invoiceDate.add({ days: 30 });
而当你确实需要一个精确的时间点而非日历日期时:
const now = Temporal.Now.instant();
这种区别的重要性远超表面所见。
计费系统其实并不需要“JavaScript Date对象”。
它需要的是日历日期。
分布式事件日志也不需要“日历日期”,它需要的是时间点。
Temporal强制要求你明确指出自己究竟指的是哪一种时间值。
对于任何涉及支付、订阅、预订、市场或跨时区用户的场景,这不仅仅是一种更美观的语法——它还能避免一类错误,即使用错误类型的时间值。
2. 你的`.ts`文件不一定需要构建步骤
多年来,在Node环境中运行TypeScript一直遵循这样的流程:
app.ts
↓
TypeScript
↓
app.js
↓
Node
那种工作流程至今仍然完全有效。
不过现在 Node 可以直接运行 TypeScript 文件,只要这些文件使用的是可删除的语法即可。
以这个文件为例:
interface User {
id: number;
name: string;
}
function greet(user: User) {
return `Hello ${user.name}`;
}
console.log(
greet({
id: 1,
name: "Priyanshu"
})
);
你可以直接用以下方式执行它:
node app.ts
Node 会直接去掉类型注解,然后运行剩下的纯 JavaScript 代码。
需要再次强调的一点是:Node 并不会为你进行任何类型检查。
因此对于大型生产级代码库,你仍然需要在工作流程中使用 tsc 或类似的类型检查工具。
但考虑一下较小的场景:内部脚本、简单的命令行工具或单文件实用程序。
以前的处理方式是这样的:
script.ts
↓
configure compiler
↓
compile
↓
run
现在则可以变成这样:
script.ts
↓
node
这只是一个小变化而已。
但这又是 Node 在默默移除许多项目原本就并不真正需要的那一层功能的一个例子。
3. 您的缓存代码看起来过于复杂了
您几乎肯定已经多次编写过这种模式:
let user = cache.get(userId);
if (user === undefined) {
user = await fetchUser(userId);
cache.set(userId, user);
}
这段代码本身没有问题。
但实际意图被检查、获取和存储等操作所掩盖。
您真正想表达的是:
把这个值给我。如果它还不存在,就去创建它。
现代 JavaScript 开始允许您直接这样表达。
作为 Node.js 26 组件发布的 V8 14.6 添加了以下功能:
Map.prototype.getOrInsert()
Map.prototype.getOrInsertComputed()
借助这些功能,同步缓存查询可以简化为类似这样的形式:
const value = cache.getOrInsert(
key,
createValue()
);
而当该值只需在需要时才延迟计算时:
const value = cache.getOrInsertComputed(
key,
() => createValue()
);
这些功能单独来看都算不上什么突破性创新。
但语言设计很少通过突破性的功能来进步。
只有当足够多的开发者反复编写相同的五行代码时,语言才会最终做出回应:
“好吧。你们不再需要编写那五行代码了。”
这正是那种能悄然融入日常代码的改进。
一年后,几乎没人会再谈论它。
人们会直接使用它而不会多想。
4. Node.js 现在可以深入到 JavaScript 之下
接下来的这项功能意义更为重大。
Node.js 26 引入了一个实验性的外部函数接口:
node:ffi
FFI 允许 JavaScript 调用原生库直接提供的函数。
其大致结构如下:
JavaScript
↓
node:ffi
↓
Native library
↓
C / C++ / system APIs
想象一个提供类似以下功能的原生库:
double calculate(double value);
至少从理论上讲,JavaScript现在可以加载该库并直接调用其中的函数。
这为以下应用打开了可能性:
- 专业的数值计算
- 重用现有的原生库
- 更深入的系统集成
- 原生级别的加密技术
- 图像与视频处理
但这也存在一个严重的隐患。
你正在跨越托管JavaScript与原始原生内存之间的界限。
如果函数签名出错,不会得到友好的JavaScript异常提示。
这可能会导致整个进程崩溃。
正因如此,该API仍处于实验阶段,并且需要通过特定标志才能使用。
所以请不要将此内容理解为:
“是时候用C语言重写所有npm包了。”
其实可以这样理解:
“Node现在提供了更直接的途径来操作原生环境。”
这是两种截然不同的说法。
5. 你的Node CLI可能无需安装Node
还有另一个值得质疑的假设:
如果你用Node开发工具,那么用户也必须安装Node。
单可执行文件应用则颠覆了这一假设。
Node的SEA工具允许你将应用打包为独立的二进制文件。
因此,与其分发:
npm install
node index.js
你可以分发更接近以下形式的内容:
./my-cli
以团队日常使用的内部工具为例。
它可能是一个部署CLI:
deploy production
或者一个数据库辅助工具:
db-migrate
或者使用项目脚手架工具:
project init
如果你提供的只是一个可执行文件,用户无需知道也不必关心其背后运行的是 JavaScript。
这会悄然改变 Node 的自我定位。
Node 最初的定位是:
在浏览器之外运行的 JavaScript。
现在它越来越像:
一个恰好能运行 JavaScript 的通用应用程序运行时环境。
这显然是一个更宏大的宣称。
6. 如果你的应用不再需要所有权限怎么办?
安全模型通常遵循以下模式:
Application
↓
Gets permissions
↓
Keeps permissions
↓
Runs
但如果某个权限仅在启动时短暂需要呢?
以一种在初始化时会读取配置文件及某些证书的服务为例。
一旦程序开始运行,它可能就完全不再需要访问文件系统了。
Node 的权限模型正朝着允许应用程序在运行时通过诸如 permission.drop() 这样的 API 主动缩小自身功能的方向发展。
其工作流程大致如下:
Start
↓
Read configuration
↓
Initialize
↓
Drop unnecessary permissions
↓
Run
这体现了一个有用的安全原则:
不要只询问应用程序被允许做什么,而要问它未来实际上还需要哪些权限。
API 接口的变动其实很小。
但人们对应用程序安全的思维方式却在发生重大变化。
7. Node.js 终于愿意删除某些功能了
添加 API 是让运行时看起来更出色的简单方法。
而删除它们才是困难的部分。
Node.js 26 不断移除那些存在已久的旧 API 和过时的内部机制。
这比看上去要重要得多。
每一个旧API迟早都会成为他人无法避免的依赖。
如果不加以管控,运行时最终会背负数十年来积累的种种历史包袱:
old API
+
new API
+
replacement API
+
deprecated API
+
"don't use this anymore" API
一个成熟的平台需要具备清理这些积压内容的决心。
Node.js正逐渐展现出这样的决心。
对于那些不想记住每项旧有任务处理方式的人来说,这是个好消息。
有趣之处并不在于某个单一功能
Temporal本身并无出众之处。
getOrInsert()也是如此。
不经过构建步骤直接运行也不例外。
将CLI打包为可执行文件同样不算什么特别之处。
但把它们放在一起看的话……
Node正在同时在抽象层面上不断上升:
Temporal
Better collections
TypeScript
Modern JavaScript
同时也向更低层次发展:
FFI
Native libraries
Permissions
Executable packaging
这才是真正的关键所在。
Node.js 不仅在执行 JavaScript 方面越来越出色,
它还逐渐成为支撑应用程序周边所有功能的更优秀的运行时环境。
这也就改变了在新项目开始时应提出的问题。
不必直接问:
“我需要哪个 npm 包来完成这个功能?”
如今更值得先问的是:
“Node.js 能不能直接实现这个功能?”
有时诚实的答案仍然是“不能”。
但越来越多的情况下,答案却是:
“其实……可以。”
这可以说是 Node.js 26 最令人惊叹的特点。
运行时环境已经向前发展了,
而我们的思维模式却尚未跟上。