Found 38 bookmarks
Custom sorting
Perflink
Perflink

Хороший сайт для создания простых перформанс бенчмарков на js. Не уверен, что это прям самый лучший сервис для бенчмарков, но он достаточно удобный, и если вам не нужна супер большая точность - то выглядит гуд.

Приятный интерфейс и возможность делиться ссылкой на конкретный бенчмарк без авторизации.

·perf.link·
Perflink
How we optimized package imports in Next.js – Vercel
How we optimized package imports in Next.js – Vercel

Статья от Vercel про вред от паттерна barrel file. В статье vercel рассказывают, как они оптимизировали импорты в next.js чтобы избежать обработки таких файлов и как ускорили сборку и старт приложения на 30-40%

barrel-file - это когда, например, в корне библиотеки лежит index.js, который ре-экспортит кучу сущностей из других вложенных файлов. Проблема в том, что не смотря на то, что в коде используется всего лишь 1 ре-экспортируемая сущность, бандлерам и некоторым тулам, например jest, приходится сначала обработать все файлы. Что снижает скорость работы инструмента

Каноничный пример

export { default as module1 } from './module1'; export { default as module2 } from './module2'; export { default as module3 } from './module3';

Некоторые библиотеки имеют около десяти тысяч ре-экспортящихся сущностей, что значительно влияет на скорость импорта такой библиотеки.

Команда next.js ввела новую опцию в конфиг: optimizePackageImports, которая заставляет фреймворк просканировать barrel-file и в рамках сборки поменять импорты на более точечные. Это изменение позволило ускорить сборку на 15-70%. Например, импорт @material-ui/icons ускорился с 10 секунд до 2.9 секунды.

Также в статье указана ссылка на eslint-плагин, который умеет оптимизировать импорты barrel-файлов

·vercel.com·
How we optimized package imports in Next.js – Vercel
Speeding up the JavaScript ecosystem - The barrel file debacle
Speeding up the JavaScript ecosystem - The barrel file debacle

Новая статья про ускорение JS экосистемы. На этот раз автор не разбирает какой-то конкретный кейс, а в целом рассказывает об одном паттерне, который замедляет исполнение кода.

Паттерн сегодняшней статьи - это index-файлы с ре-экспортами. В сообществе есть консенсус большинства, что у библиотек или модулей должен быть index.js, который содержит все публичное API, и дальше лезть никому не нужно. А если вы используете не все из этого API, то tree-shaking вырежет все лишнее.

В целом, это так и есть, но не всегда. Tree-shaking актуален только для кода, который был обработан бандлером. Если же код не обрабатывается бандлером, то рантайм вынужден все import'ы обработать, что увеличивает время выполнения кода.

Например, если код не бандлить и просто поставлять модулями в браузер, то браузеру придется обработать все дерево зависимостей index.js файла, даже если вам нужна одна простая утилка.

Также это проблема, с которой я сталкиваюсь при написании тестов в jest. Код импортирует 1 утилку, но она импортируется из index.js файла, поэтому jest тратит 5-10 секунд на резолв всех зависимостей, и 100мс на запуск самих тестов.

При этом index.js файлы - это не анти-паттерн. Да, у него есть минусы, но они проявляются только если они используются в окружениях, где код запускается без бандлинга и если таких файлов неприлично много. Если index.js используются к месту или в проекте, который не живет без бандлинга - то такие файлы не будут создавать негативный эффект.

·marvinh.dev·
Speeding up the JavaScript ecosystem - The barrel file debacle
Как показать миллион зданий на карте — и не сломать браузер
Как показать миллион зданий на карте — и не сломать браузер

Статья от 2ГИС про то, как разные агрегации по миллионам объектам на карте. 2ГИС часто радует своими статьями с интересными высоконагруженными кейсами, и эта статья - не исключение, хотя коротковата

В статье рассказывается, как можно обрабатывать огромные массивы данных в браузере. Если коротко, то решение 2ГИС в использовании следующих инструментов: WebWorkers, передача данных в бинарном виде, обработка на GPU

·habr.com·
Как показать миллион зданий на карте — и не сломать браузер
How we reduced the size of our JavaScript bundles by 33%
How we reduced the size of our JavaScript bundles by 33%

Статья от команды Dropbox о том, как они сменили бандлер и уменьшили размер JS статики на треть.

Dropbox - крупная компания со своими сложными вызовами и поэтому, в 2014 году они сделали свой бандлер и свою технологию Dropbox Web Server (DWS). DWS позволяет делать модульный веб - страница состоит из независимых страничных блоков (pagelet), которые разрабатываются и обрабатываются независимо друг от друга.

Кастомный бандлер сильно отстал от лидеров рынка и поэтому было принято решение переезжать на современные решения. Самые крупные проблемы предыдущей архитектуры:

  1. Дублирующийся код. Т.к. pagelet-ы независимы друг от друга, то если у них есть общий код, то они его встраивают в себя, вместо того чтобы переиспользовать
  2. Отсутствие автоматического код-сплиттинга. Бандлер поддерживал его, но только через ручной конфиг на 6000 строк
  3. Отсутствие три-шейкинга

Все эти проблемы давно решены текущими сборщиками, но не были решены в самописном решении. Dropbox переехал на использование rollup, но при этом миграция на него была плавная: сначала только dev сборка, затем только для сотрудников, затем раскатка на пользователей.

Во время плавной миграции были следующие трудности:

  1. Иногда rollup падал из-за высокого потребления памяти в CI
  2. Сложно поддерживать одновременно 2 бандлера
  3. Появились баги из-за слишком агрессивного три-шейкинга у Rollup
  4. Rollup включал strict mode для кода, что ломало некоторые зависимости

Как результат:

  1. Удалось уменьшить JS статику на 33%
  2. Количество JS файлов уменьшилось на 15%
  3. Улучшился TTVC (time to visual complete). Я так понял это одна из основных метрик, за которыми следит dropbox
·dropbox.tech·
How we reduced the size of our JavaScript bundles by 33%
Practical Guide to not Block the Event Loop
Practical Guide to not Block the Event Loop
Гайд по неблокирующей работе с event loop. Event Loop можно нечаянно заблокировать каким-нибудь сложным вычислением, что приведет к деградации работы сервиса. Чтобы этого избежать можно использовать 2 решения. Первое решение: сделать ресурсоёмкий код асинхронным, т.е. чтобы он выполнялся не за один "тик" цикла событий, а сделать так чтобы выполнялся итерационно с постановкой задачи в цикл событий. Тогда ресурсоёмий код не будет блокировать цикл событий и движок сможет разобрать дргуие события Второе решение: вынести ресурсоёмкий код в worker. У worker'ов есть свои ограничения (недавно в канале была хорошая ссылка на этот счет), но зато есть один неоспоримый плюс - worker не блокирует цикл событий.
·bbss.dev·
Practical Guide to not Block the Event Loop
Making Tanstack Table 1000x faster with a 1 line change
Making Tanstack Table 1000x faster with a 1 line change
Ускорение Tanstack Table в 1000 раз одной строчкой кода! Автор использует Tanstack Table в своем приложении с большими таблицами и заметил, что приложение подвисает на 30-40 секунд, если включить группировку колонок в таблице. Он пошел разбираться, используя старый дедовский метод выводя тайминг в console, почему так лагает. В процессе поиска он постоянно натыкался на места, которые казались ему медленными. "Ага, тут рекурсивный цикл, это точно он!" (нет). "Ага, это reduce вместо обычного цикла!" (нет). В итоге выяснил, что для трех сгруппированных колонок вызывается метод `groupBy`, каждый из которых отрабатывает по 10 секунд. Оказалось, что группировка лагала из-за использования оператора spread `map.set(resKey, [...previous, row])`. Этот оператор используется в reduce для добавления элемента к массиву в одном из значений `Map`. Оператор spread создает новый массив. Поэтому, например, если в результирующем массив будет 1000 элементов, будет создано 1000 массивов. В данном коде не нужна была иммутабельность, поэтому 1 строчное изменение spread оператора на push (`previous.push(row)`) ускорило код в 1000 раз (10 секунд = 10 ms).
·jpcamara.com·
Making Tanstack Table 1000x faster with a 1 line change
Speeding up the JavaScript ecosystem - npm scripts
Speeding up the JavaScript ecosystem - npm scripts
Продолжение серии статей про ускорение экосистемы JS. На этот раз выбор автора пал на то, как npm запускает скрипты (например через `npm run`). Оказывается, для того чтобы запустить скрипт npm тратит около 400мс. С одной стороны, не так уж много, с другой стороны, что там делать 400мс? Автор проводит несколько оптимизаций, которые уменьшают время запуска до 137мс. Но возможности оптимизаций ограничены временем на борьбу с архитектурой пакета npm. Если писать подобное решение с нуля, удалив все "лишнее", то можно уместиться в 22 мс. Что конкретно сделал автор. 1. Классическая проблема JS экосистемы - все `require` и `import` описываются в начале файла, что заставляет движок сразу подгружать код, хотя он может быть еще не нужен. В npm эта проблема так же повторяется - мы просто хотим запустить скрипт, но npm делает require разных утилок, которые, например, нужны для обработки ошибок. Простой перенос require в то место, где код действительно понадобится, позволяет ускорить работу основного скрипта. 2. Класс, который обрабатывает команды npm, является супер-классом и тянет в себя много функционала. Вы хотите просто запустить скрипт? Держите audit, dedupe, workspaces и другие крутые функции, которые вам сейчас не нужны. Вынос этого функционала дал 20мс 3. Еще 1 вещь, которая замедляет npm - это сортировка строк. Опять же, хороший вопрос, зачем нам там что-то сортировать, когда мы вызываем конкретный скрипт из package.json. Для сортировки используется `Intl. Collator`, это позволяет сортировать строки с учетом локали пользователя. Но там сортируется массив названий команд и с этим хорошо справляется обычный `.sort`. Таким образом выиграли еще 10 мс. К этому моменту время запуска сократилось до 200мс 4. Следующий найденный, но не исправленный момент - установка названия процесса. Чтобы процесс не назывался `npm` или `node`, npm ставит процессу корректное название, позволяющее легче с ним работать, например, при мониторинге работы процессов. Это очень полезная фича, но она занимает 10мс 5. Дальше было найдено, что функция glob также тратит много времени работы. npm управляет логами запуска скриптов и это очень полезная фича. Иронично, что она тратит много времени на сортировку массива из десятка элементов через `Inlt.Collator`. Замена на обычный `.sort()` сохранила еще 10 мс. К этому момент время запуска сократилось до 137мс (не спрашивайте "как?", я тоже не понял, но вот между 3 и 5 шагом есть всего 1 оптимизация на 10мс, но разница - 63мс. Возможно там 6 раз делалась сортировка, возможно автор делал что-то еще, что решил не отображать в статье) Дальше автор приходит к выводу, что для дальнейшего ускорения нужно заняться очень агрессивным удалением или комментированием кода. Поэтому он пишет с нуля свою минимальную имплементацию и получает 22мс.
·marvinh.dev·
Speeding up the JavaScript ecosystem - npm scripts
Почему Banditypes — самая маленькая TS-библиотека для валидации схем
Почему Banditypes — самая маленькая TS-библиотека для валидации схем
Статья про создание самой маленькой либы для валидации схем. В целом это статья не про валидацию схем, а про проектирование библиотеки с минимальным размером. Конкретно здесь автор влез в 400 байт.
·habr.com·
Почему Banditypes — самая маленькая TS-библиотека для валидации схем
Speeding up the JavaScript ecosystem - eslint
Speeding up the JavaScript ecosystem - eslint
3 пост в серии "ускорение JS экосистемы". Напомню, что автор доказывает, что не надо переписывать JS экосистему на go, rust, etc, вместо этого следует заняться оптимизацией текущей экосистемы на JS. В этот раз автор ускоряет eslint - инструмент, который есть, наверное, в каждом крупном проекте. Было найдено несколько проблем. 1. Поиск нужного токена комментария в правиле JSDoc Почему-то при парсинге комментариев для правила проверки JSDoc класс `BackwardTokenCommentCursor` аллоцируется более 20 миллионов раз. Переделка работы поиска нужного токена вынесена из текущего поста, но в целом, главная проблема - это лишние вызовы класса. Т.к. аллоцируется так много элементов то поиск по ним идет долго. В коде eslint используется метод `findIndex`, который линейно перебирает токены. Автор переписал поиск на бинарный поиск и ускорил работу этого участка кода в 2 раза. 2. Движок селекторов В eslint есть поддержка синтаксиса для матчинга AST-нод аля "css-селекторы". Это достаточно удобная фича, но движок селекторов также требует оптимизации. Медленный участок кода в селекторе - функция `getPath`. Это функция, которая достает свойство объекта по его строковому пути. Например `getPath({a: {b: true}}, 'a.b') === true`. В этой функции было 2 проблемы, которые влияли на перформанс: 1. Старый транспайленный код. Проект, видимо, давно не публиковался с новыми транспайлерами с таргетом под современные рантаймы, а цикл `for-of` при транспиляции заменяется на генераторы, что сильно медленнее нативного `for-of`. Это частая проблема в экосистеме. Замена на for-of значительно ускорила код. 2. `for-of` делается по `path.split('.')`, что вызывает алокации памяти. Вместо этого автор переписал код на ручной проход по строке с поиском точек и выделением части пути. Итог этой оптимизации: 2.7с = 486мс Также был сделан ранний выход из движка. Движок селекторов очень мощный, но часто при написании eslint правил разработчикам достаточно матчить только тип AST-ноды, а это можно делать вообще без запуска движка. Далее автор приходит к логичной мысли, что eslint когда-то решил что удобно писать точечные селекторы с css-семантикой. В целом это удобно, но eslint также мог бы дать простое API для JS-селекторов. Ну т.е. зачем нам придумывать какой-то движок, повторяющий семантику css селекторов, если можно просто писать нативный JS код, проверяющий что нам нужно. Автор проверил, будет ли это работать быстрее - и это действительно так. Простая JS функция в 30 раз быстрее, чем движок селекторов. 3. Конвертация AST в AST Eslint использует свой формат AST, в который другие парсеры вынуждены переводить свои AST. И если babel-parser имеет почти такой же AST, то вот typescript-parser имеет свой AST и при парсинге файлов переводит свой TS-AST в расширенный AST для eslint. Это влияет на перформанс дважды: нужно хранить 2 дерева AST и нужно делать дополнительную работу по переводу AST в AST. Автор сравнил скорость работы typescript eslint parser и babel eslint-parser и выяснил, что последний работает в три раза быстрее. Так что, если вам не нужны правила, которые имеют информацию о типах (киллер фича typescript parser, он, например, позволяет проверять, что никто не проходит for in по массиву), то можете заменить парсер на babel и ускорить свой линтинг. Рекомендую к прочтению в оригинале. Хорошая статья и хорошие примеры оптимизации перформанса.
·marvinh.dev·
Speeding up the JavaScript ecosystem - eslint
Speeding up the JavaScript ecosystem - one library at a time
Speeding up the JavaScript ecosystem - one library at a time
Сейчасть есть модный тренд на переписывание инструментов для сборки на Rust или Go. Типа если мы перепишем инструмент на язык, который ближе к железу, то он будет работать быстрее. Однако JIT в текущих JS движках тоже достаточно быстрый, и возможно проблема не в языке, на котором написан инструмент, но в самом коде. В статье автор разбирает, как он с помощью профайлера находил проблемы с перформансом в текущих библиотеках и как исправлял код в них, чтобы они работали быстрее. В статье достаточно подробное описание, что за проблема, почему это проблема и как её решать. Также есть ссылки на PR-ы в инструменты Честь и хвала таким героям, которые оптимизируют инструменты, которые афектят на все сообщество. Основной посыл статьи - вместо того, чтобы переписывать инструменты на другие языки, следует все таки посмотреть, что можно оптимизировать в текущем стеке. Рекомендую к прочтению
·marvinh.dev·
Speeding up the JavaScript ecosystem - one library at a time
Wix Multithreaded Node.js to Cut Kubernetes Pod Costs
Wix Multithreaded Node.js to Cut Kubernetes Pod Costs
Команда Wix применила worker threads в своём nodejs приложении и уменьшила потребление ресурсов этим приложении в своем kubernetes кластере на 70%. Статья достаточно короткая. В рамках неё разбирается что же такое worker threads (механизм в nodejs для вынесения сложных вычислений в треды из основного потока) и какие есть готовые решения для использования этой технологии. Перевод приложения на треды нетривиален (треды требуют чтобы между процессом и тредом летали "чистые" данные, что может потребовать значительного рефакторинга кода), но для Wix он определенно стоил того. В конце статьи раскрываются изменения различных показателей сервиса. Например, теперь требуется на 70% меньше подов, улучшились метрики по скорости ответа, в 10 раз уменьшился рейт ошибок. Эти цифры и есть самое важное в статье. Если у вас есть сложные вычисления на nodeJS, то вы можете также расчитывтаь на значительноее улучшение перформанса при переводе вычислений в треды.
·thenewstack.io·
Wix Multithreaded Node.js to Cut Kubernetes Pod Costs
MemLab: An open source framework for finding JavaScript memory leaks
MemLab: An open source framework for finding JavaScript memory leaks
Meta опубликовали свой инструмент для поиска утечек памяти в JS приложениях под названием MemLab в открытый доступ. Как я понял, MemLab использует puppeteer для навигации по сайту, а затем сравнивает снапшоты памяти для поиска потенциальных кандидатов на утечку. Также MemLab предоставляет удобный интерфейс для анализа "утёкших" объектов. В статье нет глубоких технических подробностей о работе инструмента, но зато есть кейс самой Мета - они уменьшили количество крашей страниц на Facebook из-за нехватки памяти в 2 раза с помощью MemLab. Также есть несколько конкретных кейсов: утечка памяти из-за React Fiber реализации и утечка памяти из-за Relay
·engineering.fb.com·
MemLab: An open source framework for finding JavaScript memory leaks
React re-renders guide: everything, all at once
React re-renders guide: everything, all at once
Хорошая статья про ререндеры react-компонентов. В статье описываются основные источники ререндеров и как нужно структурировать код, чтобы избежать лишних ререндеров. Плюсы статьи: - Это не просто заметка в стиле "вот проблема, вот 2 решения". Тут достаточно подробно описаны как причины, так и решения. Описано много способов, как можно решить проблему лишних ререндеров. - Очень хорошая визуализация. Даже если вы все знаете о рендере в реакте или, наоборот, реакт вам вообще не интересен, советую хотя бы глянуть визуализацию. Выглядит потрясающе
·developerway.com·
React re-renders guide: everything, all at once
Deeper testing of Bun's performance and compatibility against Node.js
Deeper testing of Bun's performance and compatibility against Node.js
Продолжение сравнения bun и node.js. Статья от того же чувака, которого я уже постил. И даже кейс тот же - он переводит свой сайт. Но эта статья - она типа v2.0 прошлой статьи про bun vs node.js Что тут нового: - Разбор перформанс тестов. Например, там есть набор тестов, тестирующих скорость доступа к sqlite, т.е. тестируются библиотека для nodejs, библиотека для deno и встроенное в bun нативно решение на rust - Автор чуть более подробно рассказывает про то, как он тестировал совместимость bun и node.js на своем проекте. К чести bun, автор оформлял им реквесты в github и к моменту публикации статьи некоторые уже были пофиксены. - Автор сделал свой бенчмарк (или он у него уже был), где проверяются основные инструменты, использующиеся в его проекте (рендер блога). Из 11 сценариев на bun он смог перенести всего 6. Но при этом те, которые были перенесены - в целом выполнились быстрее (в среднем на где-то 10%, но один бенч выполнился в 2 раза быстрее) Далее автор описывает свой опыт работы в Java, где есть спека и есть куча рантаймов, его имплементирующих. И есть тесты для этих рантаймов. И вот как было бы круто, если бы была спека node.js (хотя он не язык и ему незачем) или хотя бы какая-то хорошая табличка совместимости, за которой можно следить.
·techsparx.com·
Deeper testing of Bun's performance and compatibility against Node.js
Faster initialization of instances with new class features · V8
Faster initialization of instances with new class features · V8
После того как публичные и приватные свойства класса вошли в стандарт, команда V8 начала работу над оптимизацией их реализации в движке. До оптимизации, реализацией полей классов была намного медленее реализации заполнения полей обьекта. В новом v8 заполнение полей объекта остается более быстрым вариантом, но разница уже минимальна. В статье приводятся графики и обьяснение оптимизации и внутренней имплементации полей класса.
·v8.dev·
Faster initialization of instances with new class features · V8
Using global memoization in React
Using global memoization in React
Статья про мемоизацию в React. В React есть хук useMemo, но его применение весьма ограничено: мемоизация не переиспользуется между компонентами и, кроме того, мемоизация сохраняет только одно последнее значение. В статье рассматриваются альтернативные методы мемоизации (хотя я бы не все из них назвал мемоизацией) и рассказывается про LRU кэширование.
·thoughtspile.github.io·
Using global memoization in React
JavaScript нанобенчмарки и преждевременные тормоза
JavaScript нанобенчмарки и преждевременные тормоза
Здравствуйте, меня зовут Дмитрий Карловский и раньше я… ежедневно измерял свою пипирку, но у распространённых линеек никак не хватало точности для измерения стол...
·habr.com·
JavaScript нанобенчмарки и преждевременные тормоза
FrontendConf 2018 — Конференция фронтенд-разработчиков
FrontendConf 2018 — Конференция фронтенд-разработчиков
У javascript насквозь асинхронная природа, но при этом один поток - как же так? Как пользоваться асинхронностью и не выстрелить себе в ногу? Мы рассмотрим, что такое event loop, и с чем его едят, поглядим, чем таски отличаются от микротасок, как браузеры управляют приоритетами задач, и что говорит на этот счет спецификация. Также узнаем, в чем отличия в работе event loop в Node.js, и проведем параллели с браузерами.
·frontendconf.ru·
FrontendConf 2018 — Конференция фронтенд-разработчиков
Не попадайте в ловушку преждевременной оптимизации
Не попадайте в ловушку преждевременной оптимизации
Дональд Кнут однажды сказал слова, ставшие впоследствии знаменитыми: «Настоящая проблема заключается в том, что программисты, не там, где нужно, и не тогда, когд...
·habr.com·
Не попадайте в ловушку преждевременной оптимизации