Функции Node.js 26, которые тихо заменяют годы использования обходных решений
Функции Node.js 26, устраняющие старые обходные решения: API Temporal для работы с датами, нативная обработка TypeScript, встроенные инструменты кэширования и несколько дополнительных мелких улучшений.
Источники: You’re Still Writing Node.js Like It’s 2020
1. Мы наконец можем перестать притворяться, что Date — это настоящий API дат
Вот обычный JavaScript:
const date = new Date("2026-09-08");
console.log(date);
Теперь попробуйте ответить на немного более сложный вопрос:
Какова местная дата встречи, проходящей в Нью-Йорке?
Или:
Добавьте три месяца к этой дате счета.
Или:
В чем на самом деле разница между календарной датой и точным моментом времени?
Именно здесь Date начинает давать сбои.
Именно поэтому Temporal так важен.
Node.js 26 по умолчанию включает API Temporal, наконец предоставляя 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();
Это различие важнее, чем кажется.
Системе инвойсинга на самом деле не нужен «объект Date в JavaScript».
Ей нужна дата по календарю.
Распределённому журналу событий не нужна «дата по календарю».
Ему нужен момент времени.
Тип temporal заставляет вас чётко указывать, что именно вы имеете в виду.
Для всего, что связано с оплатами, подписками, бронированиями, рынками или пользователями, расположенными в разных часовых поясах, это — не просто более удобная синтаксис.
Это исключает целую категорию ошибок, при которых используется неверный тип временных значений.
2. В вашем файле .ts не обязательно требуется шаг сборки
В течение многих лет запуск TypeScript в Node подразумевал следующую цепочку операций:
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 позволяет выразить именно это.
V8 14.6, входящий в состав Node.js 26, добавляет:
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 включает экспериментальный интерфейс Foreign Function Interface:
node:ffi
FFI позволяет JavaScript вызывать функции, напрямую предоставляемые нативными библиотеками.
Вот пример его работы:
JavaScript
↓
node:ffi
↓
Native library
↓
C / C++ / system APIs
Представьте себе нативную библиотеку, которая предоставляет что-то вроде:
double calculate(double value);
Теперь JavaScript, по крайней мере теоретически, может загрузить эту библиотеку и напрямую вызвать соответствующую функцию.
Это открывает возможности для таких вещей, как:
- специализированные числовые вычисления
- повторное использование существующих нативных библиотек
- глубокая интеграция с системой
- шифрование на уровне нативного кода
- обработка изображений и видео
Но к этому существует серьезное ограничение.
Вы переступаете границу между управляемым JavaScript и чистой нативной памятью.
Если вы ошибетесь с сигнатурой функции, в ответ не появится вежливое исключение от JavaScript.
Это может привести к сбою всего процесса.
Именно поэтому этот API остается экспериментальным и доступен только при включении соответствующего флага.
Поэтому не стоит воспринимать это как:
«Пора переписать каждый пакет npm на языке C».
Лучше понимать это так:
«Node теперь предоставляет гораздо более прямой путь в сферу нативных приложений».
Это два совершенно разных утверждения.
5. Для вашей CLI Node может и не требоваться установленный Node
Вот ещё одно предположение, которое стоит поставить под сомнение:
Если вы создаёте инструмент с помощью Node, то ваши пользователи тоже должны иметь установленный Node.
Приложения в формате одного исполняемого файла противоречат этому предположению.
Инструменты SEA от Node позволяют упаковать приложение в виде автономного бинарника.
Так что вместо того, чтобы отправлять:
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 направлена на то, чтобы позволять приложениям активно сокращать свои возможности во время работы с помощью таких API, как permission.drop().
Процесс выглядит примерно так:
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().
То же самое — запуск файла .ts без этапа сборки.
То же самое — пакетирование CLI в виде исполняемого файла.
Но если поставить их рядом...
Node одновременно движется вверх по шкале абстракции:
Temporal
Better collections
TypeScript
Modern JavaScript
и в то же время — вниз:
FFI
Native libraries
Permissions
Executable packaging
Вот в чём суть дела.
Node.js не просто становится лучше в выполнении JavaScript.
Он превращается в более совершенную среду выполнения для всего, что связано с вашим приложением.
Это меняет вопрос, который стоит задать в начале нового проекта.
Вместо того чтобы сразу спрашивать:
"Какой пакет npm мне нужен для этого?"
всё чаще имеет смысл сначала спросить:
"Может ли Node.js уже это сделать?"
Иногда честный ответ всё равно будет отрицательным.
Но всё чаще ответ оказывается таким:
"На самом деле... да."
Это, пожалуй, самое примечательное в Node.js 26.
Среда выполнения уже развилась дальше.
Наши умственные модели просто ещё не успели за ней поспеть.