Pull to refresh
16K+
5
Ярослав Золотарёв@jarick

Lead Frontend developer

Send message

Согласен, что формулировка в статье не совсем корректная, текст поправил. Паралелить код, конечно можно и на Node.js. Но смысл статьи был в другом: deno_core не замена Node, а всего лишь либа с удобным API для встраивания V8 напрямую в Rust-процесс. Когда JS выполняется внутри, а не в отдельном Node worker, мы получаем:

  1. Прямые вызовы Rust-функций из JS через ops.

  2. Более легковесные изоляты: поднять изолят из snapshot-а за 2-3 мс проще, чем менеджить пул тяжелых Worker Threads с их MessagePort.

С пулом node workers не сравнивал, так как изначально было понятно, что snapshot даст выигрыш именно на скорости создания контекста и отсутствии оверхедов.

Не думаю, что будут минуса. На самом деле тут действительно прослеживается идея, которая идёт ещё от CGI, всё циклично, в других моих статьях я это как раз и описывал. V8 jit можно вполне сравнить с opcache. Но справедливости ради, тогда уже нужно вспомнить Phalcon Framework. Тут прямая аналогия, когда роутинг, работа с базой, кеш и прочие писались на системных языках, а логика на PHP.

Чтобы избежать таких проблем с окружением, нужно было как минимум запускать всё в Docker на одном базовом образе, а как максимум использовать отдельный стенд для бенчмарков. Тогда результаты были бы воспроизводимыми и не зависели от конкретного ноутбука (производители ноутов вообще любят в самый разгар тестов сбрасывать частоты, если питание не от сети).

0. Где ссылка на исходники? Какая конфигурация, как вообще запускали?

1. То, что Node.js выигрывает у Deno примерно в 1,5 раза на задаче с обработкой текста и Map'ами, выглядит очень странно. За счёт чего такой разрыв? По сути, это один и тот же V8 под капотом, и на строковых операциях с Map результаты должны быть сопоставимы. Тем более парадоксально, что Node с V8 двухлетней давности оказывается быстрее свежего Deno.

2. Очень странная подборка версий. Особенно удивляет, что Node.js такая старая и уже не актуальна. Вы же по итогу разные версии V8 мерите, и какой в таком случае смысл?

3. Почему вы написали свой велосипед для тестирования кода? Есть же куча готовых например:
https://github.com/tinylibs/tinybench
https://github.com/evanwashere/mitata
node:benchmark

4. Если вы хотели мерить быстродействие именно Node.js и прочих, поднимите на отдельной машине сервер и ударьте по нему wrk(есть куча аналогов, кому что больше нравится) трафиком. А сейчас вы фактически мерите работу V8 и JavaScriptCore.

Я боюсь, что мы сейчас начнём холиварить, чего бы на самом деле не хотелось. В конце концов идеального инструмента для всех не существует, но думаю, и так понятно, что запускать CI более-менее большого проекта без Rust-инструментов — это большая боль.

С oxc я работаю очень плотно каждый день, полёт нормальный. Код и архитектура мне нравятся гораздо больше, чем у swc. Ничего «на скорую руку», как в том же React Compiler, я не увидел — как сделаны те же строки через atom, взрослые решения, взятые из Zig, мне безумно нравятся.

Насчёт кастомизации: если мы говорим о форматировании, то у меня честно ни разу не было кейса, когда форматтер надо кастомизировать. Если же говорить об eslint, то я написал немало кастомных правил для oxc и, на мой взгляд, они пишутся ничуть не хуже, чем для eslint.

Тем же чем eslint и babel. В oxc из коробки есть свой форматер.

ESLint, axios, npm, lodash, Babel, Prettier: в 26 году это не эра инженерной зрелости, а банальная ригидность.

Вам не кажется, что человек, который проделал титанический труд и выложил его в открытый доступ, имеет право говорить, что это его работа?

Без обид, но выглядит так, что вы забиваете микроскопом гвозди. Делать онлайн-игру на JS-рантайме, кажется как раз тот случай, когда и так приходится бороться с массой ограничений среды. Накидывать сверху свой кастомный рантайм на генераторах, который далеко не zero-cost, в таких условиях только усугубляет проблему, а не решает её.

Есть пару вопросов автору:

1. В статье указано, что арена полезна, чтобы избежать создания множества мелких Uint8Array при сериализации в бинарный формат. Тут сразу вопрос зачем нужно вообще этим заниматься. Но даже если это и нужно не будет ли в этом случае проще и эффективнее использовать стандартный пул переиспользуемых TypedArray? Ручное управление смещениями (offsets) в ArrayBuffer усложняет код, а выигрыш по сравнению с переиспользованием одного Float64Array/Uint8Array из пула кажется сомнительным.

2. Вы упомянули, что p-limit не интегрирован с корутинами и приоритетами. Это справедливо, но для 90% сценариев ограничения параллелизма (например, лимит запросов к API) приоритеты не нужны. Не получается ли, что для типовых задач ваше решение является избыточным по сравнению с тем же p-limit, который работает с обычными async/await без перехода на тяжелые генераторы?

3. В статье упоминается возможность использования SharedArrayBuffer и воркеров, но не раскрыта мотивация. Какие конкретные кейсы оправдывают использование, если для большинства задач "тяжёлых вычислений" достаточно обычного пула Web Workers с явной передачей сообщений через postMessage?

Просто с задачей верстать формочки уже и железный друг научился неплохо справляться. Как правило, фронтенд в 2026 году — это что-то из: BD UI, monorepo, FSD, свой UI kit, frontops, выстраивания пирамиды тестирования, storybook, BFF, Rust и прочие сложные вещи.

К сожалению, вопрос про varlet и const задаётся, как правило, на любом собеседовании, которыми сейчас наполнены YouTube и тематические группы в Telegram. В 2026 году количество людей, которые научились заучивать вопросы на скринингах и подготовлены менторами, увы, превысило возможности HR-отдела по обработке резюме. Тем более что графа «опыт работы» абсолютно девальвировалась и превратилась в фарс. Фактически остаётся только ужесточать требования и спрашивать базу компьютерных наук, но вызывает серьёзные опасения, что на фронтенде такие вопросы вызовут крайне негативную реакцию.

Можно провокационный вопрос оффтоп. Насколько, на взгляд автора, уместно спрашивать на собеседовании frontend-разработчика вопросы, которые были описаны в его статьях? Есть опасение получить негативный фидбек о токсичности, если начать копать так глубоко и спрашивать о V8-оптимизациях у соискателей. Есть ли у кого-то тут подобный опыт?

Клиентские запросы — это вообще боль и страдание ноды, там всегда всё плохо по тестам) Понятно, что с танцами с бубном возможно всё, но у deno_core ты получаешь это из коробки с приятным DX и кучей плюшек: снепшоты, tokio, нормальная работа с памятью.

На моей практике при работе с napi-rs всё не так приятно и гладко, как бы хотелось. По перфомансу есть большие вопросики. N-API добавляет существенный оверхед на каждый вызов из-за C ABI, к тому же делает копирование строк между V8 и Rust. Как альтернатива deno_core ops выглядит для меня гораздо более приятным в работе решением: deno изначально написан на Rust, соответственно нет промежуточных слоёв в виде C ABI, плюс tokio из коробки вместо libuv thread pool.

Жалко, очень мало подробностей. Что насчёт GC? Как именно он реализован? Как в памяти хранятся JS-структуры? Как делали аллокацию памяти под динамическую память — использовали ли bumpalo или что-то схожее? Как происходит трансляция из UTF-8 (Rust) в UTF-16 (JS)? Есть ли event loop в рантайме? Как именно и что мерили бенчмарком (wrk, отдельная машина или докер, прогрев турбофана и прочих кешей на V8)?

Сравнение было бы интересно в контексте вечного холивара Rust vs Golang. Также интересно было бы понять, даёт ли GC какой-то эффект на перфоманс в WASM. Ну и у всех решений для WASM, на мой взгляд, ахиллесова пята - это потребление памяти. Я, конечно, не питаю иллюзий, но вдруг у Гошки получится что-то с памятью сделать.

Прогоняли ли вы свой проект через js-framework-benchmark ?

Было бы интересно увидеть сравнение с leptos.

Эта логика работает только в том случае, если нет нагрузки. Если сайтом пользуются активно, то BFF на Node.js может легко стать узким местом. Именно поэтому DevOps-ы недолюбливают Node на серверах.

Next.js весьма сложен внутри. Там под капотом свой сборщик (Turbopack на Rust), свои плагины для SWC под директиву use cache. Parallel Routes и Intercepting Routes вообще крайне сложные штуки по своей сути в реализации. Его пилит выделенная команда фултайм. Так что сделать свою замену, которой начнут пользоваться ... прямо скажем, прыгнуть сильно выше головы. Для этого нужны явные преимущества перед Next.js.

По сути, из всех попыток можно отметить только Waku, но там автор мягко говоря непростой, и за ним стоит огромное комьюнити.

ИМХО, отсутствие потокового SSR, использование .clientOnly(), кэширование через react-query и кастомные мидлвари, по сути, откат к архитектуре Next.js 13 (Pages Router) до эры RSC. Просто старая добрая SPA/SSR модель.

Если мы говорим про реальное, а не косметическое ускорение на клиенте и сервере, то оптимизировать Node.js и react-query, кажется тупиковый путь. Сам Node.js объективно узкое место.

Если хочется выйти на новый уровень производительности, стоит смотреть в сторону отказа от Node.js в пользу системных языков. Например, проект Rari (https://rari.build), который пошел именно по этому пути: HTTP-сервер, роутер и рендерер RSC написаны на Rust (с встроенным снепшотом V8 для выполнения JS). По бенчмаркам это даёт ~58x ускорение на статике и ~550x на fetch по сравнению с Next.js (https://github.com/jarick/rari-vs-nextjs/blob/main/docs/article.md). За счет того, что тяжелая инфраструктурная часть работает на нативном коде, а не на асинхронном event-loop Node.js, показывается кратный рост пропускной способности и скорости отклика.

Но если развить эту идею до логического предела, то возникает еще более радикальный вопрос: а нужен ли нам вообще V8 на бэкенде? Мы платим за гибкость JS: Garbage Collection, оверхед на event-loop, проблемы с потреблением памяти на каждый запрос.

Если представить следующую эволюцию, в моём понимании это собственный AOT-компилятор (Ahead-of-Time) для React/JSX, который компилирует серверные компоненты и Server Actions напрямую в машинный код. В такой архитектуре для рендеринга на сервере вообще не нужен тяжелый JS-рантайм. Нет GC, нет event-loop, нет проблем с памятью. Сервер просто выполняет скомпилированные функции, собирает HTML/поток и отдает его с околонулевой задержкой.

При этом если говорить про DX, то лично моё мнение: у RSC и директивы ‘use cache’ он на порядок выше, чем у middleware-решений.

1

Information

Rating
334-th
Registered
Activity