На дворе 2023 год, и мы выпустили Node.js v20. Это значительное достижение, и цель этой статьи — использовать научную оценку состояния производительности Node.js. Все результаты бенчмарков содержат воспроизводимый пример и описание аппаратного обеспечения. Чтобы уменьшить количество шума для постоянных читателей, воспроизводимые шаги будут свернуты в начале всех разделов. Цель этой статьи - предоставить сравнительный анализ различных версий Node.js. Она подчеркивает улучшения и недостатки, а также дает представление о причинах этих изменений, не проводя никаких сравнений с другими рантаймами JavaScript. Для проведения эксперимента мы использовали Node.js версий 16.20.0, 18.16.0 и 20.0.0 и разделили сьюты бенчмарков на три отдельные группы: Node.js Internal Benchmark (внутренний бенчмарк) Учитывая значительный размер и отнимающий много времени характер сьюта бенчмарка Node.js, я выбрал образцы, которые, по моему мнению, оказывают большее влияние на разработчиков и конфигурации Node.js, например, чтение файла размером 16 МБ с помощью fs.readfile. Эти бенчмарки сгруппированы по модулям, таким как fs и streams. Для получения дополнительной информации о сюьте бенчмарков Node.js, пожалуйста, обратитесь к исходному коду Node.js. nodejs-bench-operations Я занимаюсь сопровождением репозитория под названием nodejs-bench-operations, который содержит бенчмарки для всех основных версий Node.js, а также последние три выпуска каждой линейки версий. Это позволяет легко сравнивать результаты между различными версиями, например, Node.js v16.20.0 и v18.16.0, или v19.8.0 и v19.9.0, с целью выявления регрессий в кодовой базе Node.js. Если вы заинтересованы в сравнительном анализе Node.js, знакомство с этим репозиторием может оказаться весьма ценным (и не забудьте поставить ему звезду, если вы считаете его полезным). HTTP-серверы (фреймворки) Этот практичный HTTP бенчмарк отправляет значительное количество запросов по различным маршрутам, возвращая JSON, обычный текст и ошибки, используя в качестве ссылок express и fastify. Основная цель - определить, применимы ли результаты, полученные с помощью Node.js Internal Benchmark и nodejs-bench-operations, к обычным HTTP-приложениям. Для выполнения этого бенчмарка использовался выделенный хост AWS со следующим оптимизированным для вычислений экземпляром: c6i.xlarge (Ice Lake) 3,5 ГГц - оптимизированный для вычислений 4 vCPU 8 ГБ памяти Canonical, Ubuntu, 22.04 LTS, amd64 jammy 1 Гб SSD тип диска В этом бенчмарке были выбраны следующие модули/пространства имен: fs — файловая система Node.js events — классы событий Node.js EventEmitter / EventTarget http — Node.js HTTP сервер + парсер misc — время запуска Node.js с использованием child_processes и worker_threads + trace_events module — Node.js module.require streams — создание, удаление, чтение потоков Node.js и многое другое url — парсер URL Node.js buffers — операции с буферами Node.js util — Node.js кодировщик/декодировщик текста Использованные конфигурации доступны по адресу RafaelGSS/node#state-of-nodejs, а все результаты были опубликованы в основном репозитории: State of Node.js Performance 2023. Прежде чем представить результаты, важно объяснить статистический подход, использованный для определения достоверности результатов бенчмарков. Этот метод был подробно описан в предыдущей статье блога, с которой вы можете ознакомиться здесь: Подготовка и оценка бенчмарков. Чтобы сравнить влияние новой версии Node.js, мы запустили каждый бенчмарк несколько раз (30) на каждой конфигурации и на Node.js 16, 18 и 20. В таблице результатов есть две колонки, которые требуют пристального внимания: улучшение (improvement) — процент улучшения по сравнению с новой версией достоверность (confidence) — сообщает нам, достаточно ли статистических данных для подтверждения улучшения. Например, рассмотрим результаты следующей таблицы: Существует риск в 0,1%, что fs.readfile не улучшился с Node.js 16 до Node.js 18 (достоверность ***). Следовательно, мы вполне уверены в результатах. Структуру таблицы можно представить следующим образом: fs/readfile.js — бенчмарк файл concurrent=1 len=16777216 encoding='ascii' duration=5 — опции бенчмарка. Каждый бенчмарк файл может иметь множество опций, в данном случае это чтение 1 параллельного файла с 16777216 байтами в течение 5 секунд с использованием ASCII в качестве метода кодировки. Для любителей статистики, скрипт выполняет независимый/непарный 2-групповой t-тест с нулевой гипотезой, что производительность одинакова для обеих версий. Если p-значение меньше 0.05, в поле "Достоверность" появится звездочка. — Написание и запуск бенчмарков Клонируйте репозиторий форка Node.js Проверьте ветку state-of-nodejs Создайте двоичные файлы Node.js 16, 18 и 20 Запустите скрипт benchmark.sh При апгрейде Node.js с 16 до 18 наблюдалось улучшение на 67% при использовании API fs.readfile с кодировкой ascii и на 12% при использовании utf-8. Результаты бенчмарка показали, что при апгрейде Node.js с версии 16 до 18 улучшение API fs.readfile с кодировкой ascii составило около 67%, а при использовании utf-8 - около 12%. Файл, использованный для теста, был создан с помощью следующего сниппета: Однако при использовании fs.readfile с ascii на Node.js 20 наблюдалась регрессия в 27%. Об этой регрессии было сообщено команде Node.js Performance, и ожидается, что она будет исправлена. С другой стороны, fs.opendir, fs.realpath и fs.readdir показали улучшение от Node.js 18 до Node.js 20. Сравнение между Node.js 18 и 20 можно увидеть в приведенном ниже результате бенчмарка: Если вы используете Node.js 16, то можете ознакомиться следующим сравнением между Node.js 16 и Node.js 20 Класс EventTarget показал наиболее значительное улучшение в части событий. Бенчмарк включал диспетчеризацию миллиона событий с помощью EventTarget.prototype.dispatchEvent(new Event('foo')). Апгрейд с Node.js 16 до Node.js 18 может обеспечить улучшение производительности диспетчеризации событий почти на 15%. Но настоящий скачок происходит при переходе с Node.js 18 на Node.js 20, который может дать улучшение производительности до 200% при наличии только одного слушателя. Класс EventTarget является важнейшим компонентом Web API и используется в различных родительских фичах, таких как AbortSignal и worker_threads. В результате, оптимизация этого класса может потенциально повлиять на производительность этих фич, включая fetch и AbortController. Кроме того, API EventEmitter.prototype.emit также получил заметное улучшение примерно на 11,5% при сравнении Node.js 16 с Node.js 20. Полное сравнение приведено ниже для справки: HTTP-серверы являются одним из наиболее существенных уровней усовершенствования в Node.js. Это не миф, что большинство приложений Node.js в настоящее время работают на HTTP-сервере. Поэтому любое изменение может легко рассматриваться как semver-major [семантическое объявление основной версии] и увеличить усилия для совместимого улучшения производительности. Поэтому используемый HTTP-сервер — это http.Server, который на каждый запрос отвечает 4 чанками по 256 байт каждый, содержащими 'C', как вы можете видеть в этом примере: При сравнении производительности Node.js 16 и Node.js 18 заметно улучшение на 8%. Однако апгрейд с Node.js 18 на Node.js 20 привел к значительному улучшению на 96,13%. Данные результаты были получены с помощью бенчмарк-метода test-double-http. Это простой скрипт Node.js для отправки HTTP GET-запросов: При переходе на более надежные инструменты бенчмаркинга, такие как autocannon или wrk, мы наблюдали значительное снижение заявленного улучшения — с 96% до 9%. Это указывает на то, что предыдущий метод бенчмаркинга имел ограничения или ошибки. Однако фактическая производительность HTTP-сервера улучшилась, и нам необходимо тщательно оценить процент улучшения с помощью нового бенчмаркингового подхода, чтобы точно измерить достигнутый прогресс. Безусловно, нет. Фреймворки могут не использовать внутренний HTTP API — это одна из причин, почему Fastify... быстрый! По этой причине в данном отчете был рассмотрен другой набор бенчмарков (3. HTTP-серверы). Согласно нашим тестам, скрипт startup.js продемонстрировал значительное улучшение жизненного цикла процессов Node.js, причем по сравнению с Node.js версии 18 до версии 20 наблюдалось увеличение на 27%. Оно еще более впечатляет в сравнении с Node.js версии 16, где время запуска сократилось на 34,75%! Поскольку современные приложения все больше полагаются на бессерверные системы, сокращение времени запуска стало решающим фактором в повышении общей производительности. Стоит отметить, что команда Node.js постоянно работает над оптимизацией этого аспекта платформы, о чем свидетельствует наша стратегическая инициатива: https://github.com/nodejs/node/issues/35711. Сокращение времени запуска не только идет на пользу бессерверным приложениям, но и повышает производительность других приложений Node.js, которые полагаются на быстрое время загрузки. В целом, эти обновления демонстрируют стремление команды Node.js повысить скорость и эффективность платформы для всех пользователей. Этот бенчмарк довольно прост. Мы измеряем время, затраченное на создание нового [mode] (режим) с помощью заданного [script] (сценарий), где [mode] может быть: process — новый процесс Node.js worker — worker_thread (рабочий поток) Node.js. А [script] делится на: benchmark/fixtures/require-builtins — скрипт, для которого необходимы все модули Node.js test/fixtures/semicolon — пустой скрипт, содержащий только одну ; (точку с запятой). Этот эксперимент может быть легко воспроизведен с помощью hyperfine или time: 💡 Warmup (подготовка) необходима для учета влияния кэша файловой системы. Модуль trace_events также претерпел заметный прирост производительности: при сравнении Node.js версии 16 с версией 20 улучшение составило 7%. Стоит отметить, что при сравнении Node.js версии 18 с версией 20 это улучшение было немного ниже — 2,39%. require() (или module.require) долгое время был виновником медленного времени запуска Node.js. Однако последние улучшения производительности позволяют предположить, что эта функция также была оптимизирована. Между версиями Node.js 18 и 20 мы наблюдали улучшение на 4,20% при запросе файлов .js, 6,58% для файлов .json и 9,50% при чтении каталогов — все это способствует более быстрому запуску. Оптимизация require() крайне важна, поскольку данная функция активно используется в приложениях Node.js. Сократив время ее выполнения, мы можем значительно ускорить весь процесс запуска и улучшить пользовательский опыт. Потоки (streams) — это невероятно мощная и широко используемая функция Node.js. Однако между версиями Node.js 16 и 18 некоторые операции, связанные с потоками, стали выполняться медленнее. К ним относятся создание и удаление потоков Duplex, Readable, Transform и Writable, а также метод .pipe() для потоков Readable → Writable. Приведенный ниже график иллюстрирует эту регрессию: Однако в Node.js 20 эта регрессия pipe была уменьшена: И как вы могли заметить, некоторые типы потоков (в частности, Transform) регрессируют в Node.js 20. Поэтому Node.js 16 по-прежнему имеет самые быстрые потоки — для этого конкретного бенчмарка, пожалуйста, не воспринимайте его результаты как утверждение "потоки Node.js в v18 и v20 такие медленные!". Это определенный бенчмарк, который может как повлиять, так и нет на вашу рабочую нагрузку. Например, если вы посмотрите на наивное сравнение в nodejs-bench-operations, то увидите, что следующий сниппет работает лучше на Node.js 20, чем его предшественники: Дело в том, что методы instantiation (инстанцирование) и destroy (уничтожение) играют важную роль в экосистеме Node.js. Таким образом, вполне вероятно, что это окажет негативное влияние на некоторые библиотеки. Тем не менее, эта регрессия внимательно отслеживается в Node.js Performance WG. Обратите внимание, что читаемый асинхронный итератор становится немного быстрее (~6,14%) на Node.js 20. Начиная с Node.js 18, в нее была добавлена новая зависимость парсера URL — Ada. Это дополнение подняло производительность Node.js при парсинге URL на новый уровень. Некоторые результаты могут достигать 400%. Как обычный пользователь, вы можете не использовать его напрямую. Но если вы применяете HTTP-сервер, то вполне вероятно, что на него повлияет это улучшение производительности. Набор бенчмарков URL довольно велик. По этой причине будут рассмотрены только результаты бенчмарка URL WHATWG. url.parse() и url.resolve() являются устаревшими и наследуемыми API. Несмотря на то, что их использование считается рискованным для любого приложения Node.js, разработчики все еще применяют их. Цитирую документацию Node.js: url.parse() использует мягкий, нестандартный алгоритм для парсинга строк URL. Он подвержен таким проблемам безопасности, как подмена имени хоста и некорректная обработка имен пользователей и паролей. Не пользуйтесь им при ненадежных входных данных. CVE не выдаются для уязвимостей url.parse(). Вместо этого используйте WHATWG URL API. Если вам интересно узнать об изменениях производительности url.parse и url.resolve, ознакомьтесь с репозиторием State of Node.js Performance 2023. Тем не менее, очень интересно посмотреть на результаты работы нового whatwg-url-parse: Ниже приведен список URL-адресов, использованных для сравнительного анализа, которые были выбраны на основе конфигурации бенчмарка. После недавнего апгрейда Ada 2.0 в Node.js 20 можно с уверенностью сказать, что при сравнении Node.js 18 с Node.js 20 произошли значительные улучшения: А бенчмарк-файл довольно прост: Единственное различие заключается во втором параметре, который используется в качестве базы при создании/парсинге URL. Стоит также отметить, что при передаче базы (withBase='true'), как правило, процесс идет быстрее, чем при обычном использовании (new URL(data)). Посмотрите все результаты в расширенном виде в основном репозитории. В Node.js буферы используются для работы с двоичными данными. Буферы — это встроенная структура данных, которая может использоваться для хранения необработанных двоичных данных в памяти, что может быть полезно при работе с сетевыми протоколами, операциями файловой системы или другими низкоуровневыми операциями. В целом, буферы являются важной составляющей Node.js и широко используются в платформе для работы с двоичными данными. Для тех из вас, кто прямо или косвенно использует буферы Node.js, у меня есть хорошие новости (в основном для первопроходцев Node.js 20). Помимо улучшения производительности Buffer.from() Node.js 20 исправил две основные регрессии из Node.js 18: Buffer.concat() Node.js версии 20 продемонстрировал значительные улучшения по сравнению с версией 18, и эти улучшения остаются очевидными даже по сравнению с версией 16: Buffer.toJSON() С Node.js 16 до Node.js 18 наблюдалось падение производительности Buffer.toJSON на 88%: Однако эта регрессия была исправлена и улучшена в Node.js 20 на порядки! Поэтому правильно утверждать, что Node.js 20 — самая быстрая версия Node.js при работе с буферами. Полное сравнение между Node.js 20 и Node.js 18 смотрите ниже: TextDecoder и TextEncoder — это два класса JavaScript, которые являются частью спецификации Web API и доступны в современных веб-браузерах и Node.js. Вместе TextDecoder и TextEncoder обеспечивают простой и эффективный способ работы с текстовыми данными в JavaScript, позволяя разработчикам выполнять различные операции со строками и кодировками символов. Декодирование и кодирование становится значительно быстрее, чем в Node.js 18. С добавлением simdutf для парсинга UTF-8 в наблюдаемом бенчмарке результаты улучшились на 364% (чрезвычайно впечатляющий скачок) при декодировании по сравнению с Node.js 16. Эти достижения стали еще более заметными в Node.js 20: производительность выросла на 25% по сравнению с Node.js 18. Полные результаты можно посмотреть в репозитории state-of-nodejs-performance-2023. Повышение производительности также наблюдалось при сравнении методов кодирования на Node.js 18. От Node.js 16 до Node.js 18, TextEncoder.encodeInto достиг 93,67% улучшения в текущем наблюдении (использование ascii с длиной строки 256): Операции бенчмаркинга в Node.js всегда вызывали у меня любопытство. Как человек, которому нравится изучать тонкости Node.js и лежащих в его основе технологий, я нахожу увлекательным углубляться в детали этих операций, особенно тех, которые связаны с движком V8. На самом деле, я часто люблю делиться своими открытиями с другими людьми в рамках выступлений и семинаров, проводимых компанией NearForm, с которой я связан. Если вам интересно, то можно найти больше информации о моих презентациях на данную тему, перейдя по этой ссылке. Кроме того, в этих бенчмарках будет использоваться метрика ops/sec, которая в основном означает количество операций, выполненных за одну секунду. Важно подчеркнуть, что это может означать лишь очень малую часть вашего машинного времени. Если вы читали мою предыдущую статью (Подготовка и оценка бенчмарков), то должны помнить раздел "Оценка результатов", где я рассматриваю проблему ops/sec в реальных приложениях — если нет, то вам стоит вернуться к нему. Парсинг строк в числа может быть выполнен с помощью + или parseInt(x, 10). Результаты предыдущих бенчмарков показали, что использование + было быстрее, чем parseInt(x, 10) в ранних версиях Node.js, как показано в таблице ниже: name ops/sec samples Using parseInt(x, 10) - small number (2 len) 283,768,532 91 Using parseInt(x, 10) - big number (10 len) 21,307,115 100 Using + - small number (2 len) 849,906,952 100 Using + - big number (10 len) 849,173,336 97 Источник Однако с выходом Node.js 20 и новой версии V8 (11.4) обе операции по производительности оказались эквивалентными, как показано в обновленных результатах бенчмарков ниже: name ops/sec samples Using parseInt(x, 10) - small number (2 len) 856,413,575 98 Using parseInt(x, 10) - big number (10 len) 856,754,259 96 Using + - small number (2 len) 857,364,191 98 Using + - big number (10 len) 857,511,971 96 Источник Одним из интересных бенчмарков, изменившихся с добавлением Node.js 20, является использование this или super в классах, как видно из приведенного ниже примера: Сравнение между super и this в Node.js 18 давало следующие операции в секунду (ops/sec): name ops/sec samples Using super 159,426,608 96 Using this 160,092,440 91 Источник Нет существенной разницы между обоими подходами и на Node.js 20. Это утверждение справедливо с небольшим различием: name ops/sec samples Using super 850,760,436 97 Using this 853,619,840 99 Источник По результатам бенчмарков видно, что производительность при использовании this на Node.js 20 значительно увеличилась по сравнению с Node.js 18. Этот прирост весьма заметен: поскольку this на Node.js 20 достигает впечатляющих 853 619 840 оп/с по сравнению с 160 092 440 оп/с на Node.js 18, что на 433% лучше! По-видимому, у него такой же метод доступа к свойствам, как и у обычного объекта: obj.property1. Также отметим, что обе операции были протестированы в одном и том же выделенном окружении. Следовательно, это вряд ли произошло случайно. В JavaScript существуют различные способы добавления свойств к объектам, каждый из которых имеет свое собственное назначение и иногда неоднозначен по своей природе. Как разработчик, вы можете заинтересоваться эффективностью доступа к свойствам в каждом из этих методов. Хорошей новостью является то, что репозиторий nodejs-bench-operations включает сравнение этих методов, которое проливает свет на их характеристики производительности. На самом деле, данные бенчмарка показывают, что доступ к свойствам в Node.js 20 значительно улучшился, особенно при использовании объектов со свойствами writable: true и enumerable/configurable: false. На Node.js 18 доступ к свойству (myObj.test) продуцировал 166 422 265 оп/с. Однако при тех же обстоятельствах Node.js 20 производит 857 316 403 оп/с! Эту и другие особенности доступа к свойствам можно увидеть в следующих результатах бенчмарка: Доступ к геттеру свойства v18 / v20 Доступ к сеттеру свойства v18 / v20 Доступ к свойству после перехода формы v18 / v20 Array.prototype.at(-1) — это метод, который был введен в спецификации ECMAScript 2021. Он позволяет получить доступ к последнему элементу массива, не зная его длины и не используя отрицательные индексы, что может быть полезным в некоторых юзкейсах. Таким образом, метод at() обеспечивает более лаконичный и читабельный способ доступа к последнему элементу массива по сравнению с традиционными методами, такими как array[array.length - 1]. На Node.js 18 этот доступ был значительно медленнее по сравнению с Array[length-1]: name ops/sec samples Length = 100 - Array.at 26,652,680 99 Length = 10_000 - Array.at 26,317,564 97 Length = 1_000_000 - Array.at 27,187,821 98 Length = 100 - Array[length - 1] 848,118,011 98 Length = 10_000 - Array[length - 1] 847,958,319 100 Length = 1_000_000 - Array[length - 1] 847,796,498 101 Источник Начиная с Node.js 19, Array.prototype.at эквивалентен старомодному Array[length-1], как показано в таблице ниже: name ops/sec samples Length = 100 - Array.at 852,980,778 99 Length = 10_000 - Array.at 854,299,272 99 Length = 1_000_000 - Array.at 853,374,694 98 Length = 100 - Array[length - 1] 854,589,197 95 Length = 10_000 - Array[length - 1] 856,122,244 95 Length = 1_000_000 - Array[length - 1] 856,557,974 99 Источник Большинство людей знают, что RegExp зачастую является источником многих узких мест в любом приложении. Например, вы захотите проверить, содержит ли определенная переменная application/json. И хотя вы можете сделать это несколькими способами, чаще всего используется либо: /application/json/.test(text) — RegEx или text.includes('application/json') — String.prototype.includes Некоторые из вас могут не знать, что String.prototype.includes практически такой же медленный, как RegExp на Node.js 16. name ops/sec samples Using includes 16,056,204 97 Using indexof 850,710,330 100 Using RegExp.test 15,227,370 98 Using RegExp.text with cached regex pattern 15,808,350 97 Using new RegExp.test 4,945,475 98 Using new RegExp.test with cached regex pattern 5,944,679 100 Источник Однако, начиная с Node.js 18, такое поведение было исправлено. name ops/sec samples Using includes 856,127,951 101 Using indexof 856,709,023 98 Using RegExp.test 16,623,756 98 Using RegExp.text with cached regex pattern 16,952,701 99 Using new RegExp.test 4,704,351 95 Using new RegExp.test with cached regex pattern 5,660,755 95 Источник В Node.js модуль crypto предоставляет набор криптографических функций, которые могут быть использованы для различных целей, таких как создание и проверка цифровых подписей, шифрование и расшифровка данных, а также генерация безопасных случайных чисел. Одним из методов, доступных в этом модуле, является crypto.verify(), который используется для проверки цифровой подписи, созданной методом crypto.sign(). Node.js 14 (*Окончание эксплуатации) использует OpenSSL 1.x. В Node.js 16 мы добавили протокол QUIC, но по-прежнему применяем OpenSSL версии 1. Однако в Node.js 18 мы обновили OpenSSL до версии 3.x (поверх QUIC), и после Node.js 18 была обнаружена регрессия, которая снизила скорость с 30 тыс. оп/с до 6~7 тыс. оп/с. Как я уже упоминал в твите, весьма вероятно, что это вызвано новой версией OpenSSL. Опять же, наша команда изучает данную проблему, и если у вас есть какие-либо соображения по этому поводу, не стесняйтесь ее комментировать: https://github.com/nodejs/performance/issues/72. Команда Node.js всегда тщательно следила за тем, чтобы ее API и основные функциональные возможности были оптимизированы для повышения скорости и использования ресурсов. С целью дальнейшего повышения производительности Node.js команда недавно представила новую стратегическую инициативу под названием "Performance" ("Производительность"), которую возглавляет Ягиз Низипли (Yagiz Nizipli). Она направлена на выявление и устранение узких мест в рантайме Node.js и основных модулей, а также на повышение общей производительности и масштабируемости платформы. Помимо инициативы Performance, в настоящее время реализуется еще несколько проектов, направленных на оптимизацию различных аспектов Node.js. Одной из них является инициатива 'Startup Snapshot', которую возглавляет Джойи Чунг (Joyee Cheung). Она направлена на снижение времени запуска приложений Node.js, что является критическим фактором для повышения общей производительности и удобства работы веб-приложений. Поэтому, если вам интересна эта тема, подумайте о том, чтобы присоединиться к встречам каждые две недели, и не стесняйтесь отправлять сообщения в канале #nodejs-core-performance на OpenJS Foundation Slack. Помимо стратегических инициатив, существует несколько пулл-реквестов (PR), которые с большой вероятностью окажут существенное влияние на производительность Node.js — в данный момент я пишу нижеследующий пост (он еще не смерджен): Ошибки Node.js — https://github.com/nodejs/node/pull/46648 Возникающие погрешности в Node.js обходятся очень дорого. Это нередко является источником критических моментов в приложениях Node.js. В качестве примера я провел исследование имплементации fetch в Node.js (undici) и обнаружил, что одной из зол в реализации Node.js WebStreams является процесс создания ошибок. Следовательно, проведя оптимизацию ошибочных объектов в Node.js, мы можем повысить общую эффективность платформы и снизить риск возникновения узких мест. Сжатие указателей — https://github.com/nodejs/build/issues/3204 Сжатие указателей — это техника, используемая в компьютерном программировании для уменьшения использования памяти программами, которые используют много указателей. Хотя это не улучшает производительность напрямую, но может косвенно ее повысить за счет уменьшения обращений к кэшу и ошибок страниц. Это, безусловно, может снизить некоторые затраты на инфраструктуру, как описано в данной теме. Увеличить дефолтный --max-semi-space-size - https://github.com/nodejs/node/pull/47277 В марте 2022 года был поднят вопрос, предлагающий увеличить V8 max_semi_space_size с целью уменьшить количество операций по сборке мусора (в частности, Scavenge) и увеличить общую пропускную способность в бенчмарке веб-инструментария. Мы пока оцениваем его влияние, и он может попасть или нет в Node.js 21. увеличить значение highWaterMark для потоков Node.js Readable/Writable - https://github.com/nodejs/node/pull/46608 Этот PR увеличивает значение по умолчанию для highWaterMark в потоках Node.js. Ожидается улучшение производительности при использовании потоков Node.js с параметрами по умолчанию. Однако данный PR является semver-major изменением и должен появиться в Node.js 21. Для получения подробных результатов бенчмарка, ждите: 'State of Node.js Performance 2023 — P2' в конце года. Несмотря на некоторые регрессии в потоках Node.js и криптомодуле, Node.js 20 может похвастаться значительным улучшением производительности по сравнению с предыдущими версиями. Заметные улучшения наблюдаются в таких операциях JavaScript, как доступ к свойствам, парсинг URL, кодирование и декодирование буферов/текста, время жизненного цикла запуска/процесса и EventTarget, среди прочих. Команда разработчиков производительности Node.js (nodejs/performance) расширила сферу своей деятельности, что приводит к увеличению вклада в оптимизацию производительности с каждой новой версией. Эта тенденция указывает на то, что Node.js продолжит становиться быстрее с течением времени. Стоит отметить, что бенчмарки фокусируются на определенных операциях, которые могут напрямую влиять или нет на ваш конкретный юзкейс. Поэтому я настоятельно рекомендую просмотреть все результаты бенчмарков в репозитории state-of-nodejs-performance и убедиться, что данные операции соответствуют вашим бизнес-требованиям. В заключение материала рекомендуем два открытых урока, которые пройдут в ближайшие дни в рамках онлайн-курсов OTUS: Построение Rest API с Express: займемся добавлением общих стандартов создания API; рассмотрим REST, принципы построения API; проанализируем технологии аутентификации в веб приложениях. Записаться на урок Основы HTML: создадим разметку страницы авторизации — разберём основы семантики и атрибуты полей формы. Разберем типичные ошибки. Записаться на урок  Редактор