Минутка саморекламы: в этом году я выступаю на FrontendConf!
Буду рассказывать про нехайповую, но, на мой взгляд, интересную тему — нативные модули в Node.js.
Даже официальный анонс уже вышел, так что больше скрывать не буду:
https://t.iss.one/FrontendConfChannel/1197
Буду рассказывать про нехайповую, но, на мой взгляд, интересную тему — нативные модули в Node.js.
Даже официальный анонс уже вышел, так что больше скрывать не буду:
https://t.iss.one/FrontendConfChannel/1197
Telegram
FrontendConf конференция
Что бизнесу тормоз, то разработчику боль
Медленные интерфейсы, CI по часу, дев-сервер еле дышит.
Как писать быстрые интерфейсы, ускорять сборку и запуск, отлаживать узкие места и делать отказоустойчивые системы? Об этом всем поговорим в рамках нашей секции…
Медленные интерфейсы, CI по часу, дев-сервер еле дышит.
Как писать быстрые интерфейсы, ускорять сборку и запуск, отлаживать узкие места и делать отказоустойчивые системы? Об этом всем поговорим в рамках нашей секции…
🔥13❤6
В своём докладе я рассказывала о том, как мы обновляли легаси-проект, вместо того чтобы переписывать его с нуля.
Да, доклад назывался «Не переписывай — обнови», и я действительно продвигаю эту идею. Но и сама не раз попадала в ситуации, когда обновление невозможно. Чаще всего это касается старых проектов, написанных не на чём-то из «большой тройки» (React, Angular, Vue). В таких случаях зачастую просто не остаётся другого выхода, кроме как переписывать всё заново.
Если проект построен на кастомном фреймворке или устаревшем решении, то он обречён на тяжёлую поддержку: современные библиотеки не интегрируются или делают это через боль, разработчики стараются обходить такие задачи стороной (типичная оценка «10 sp за простой баг» и привет вечный бэклог), а ещё продать такой проект при найме будет крайне сложно.
Совсем другое дело, если проект написан на React, пусть даже на версиях 16 или 17. Здесь ключевое преимущество в том, что обновление не требует перестраивать архитектуру и саму идеологию кода: как были компоненты — так они и остаются. Да, классовые, но это те же самые компоненты, которые можно переписывать и переносить постепенно, параллельно занимаясь и продуктовыми задачами.
На старте обновления важно сосредоточиться на тех вещах, которые напрямую влияют на то, как вы пишете код, и которые открывают путь к новым фичам. В нашем случае это было, например, внедрение нового стейт-менеджера. Как только эти базовые блоки обновлены, новые компоненты можно писать уже по современным подходам, а старые переписывать постепенно, по мере необходимости. А такие задачи, как переезд с Webpack на Vite или обновление сборки в целом, можно отложить на потом — они не меняют сам код и не блокируют разработку.
Вопрос, который мне задали на докладе, оказался очень в точку: что делать, если проект стареет быстрее, чем вы его обновляете? Тут важно определить для себя критерии «легаси». Например, если у вас библиотека пятой версии, а недавно вышла шестая — это не значит, что проект мгновенно стал легаси. Но если версия 5 уже три года официально считается устаревшей и реально мешает работе (замедляет сборку или использует подходы, которые давно вышли из употребления, как это было с классами против функциональных компонентов), вот тогда пора действовать.
И напоследок. Если у вас всё же тот самый первый вариант, когда переписывать приходится с нуля, продумайте стратегию постепенного перехода. На одном из проектов мы буквально переписывали его «по страницам». Да, и это проходило не без проблем, но так задачу можно было декомпозировать и оценивать. Параллельно брали продуктовые истории — иногда в новые страницы, иногда даже в старые (компромиссы неизбежны).
Никто не согласится на план «нам нужен год, никакие фичи не делаем, и не факт, что даже уложимся». Любое обновление должно быть разбито на понятные этапы. Так и прогресс виден: не как мифические «0 и вдруг 100%», а постепенно, по шагам. И для команды, и для менеджмента это куда легче и понятнее.
Да, доклад назывался «Не переписывай — обнови», и я действительно продвигаю эту идею. Но и сама не раз попадала в ситуации, когда обновление невозможно. Чаще всего это касается старых проектов, написанных не на чём-то из «большой тройки» (React, Angular, Vue). В таких случаях зачастую просто не остаётся другого выхода, кроме как переписывать всё заново.
Если проект построен на кастомном фреймворке или устаревшем решении, то он обречён на тяжёлую поддержку: современные библиотеки не интегрируются или делают это через боль, разработчики стараются обходить такие задачи стороной (типичная оценка «10 sp за простой баг» и привет вечный бэклог), а ещё продать такой проект при найме будет крайне сложно.
Совсем другое дело, если проект написан на React, пусть даже на версиях 16 или 17. Здесь ключевое преимущество в том, что обновление не требует перестраивать архитектуру и саму идеологию кода: как были компоненты — так они и остаются. Да, классовые, но это те же самые компоненты, которые можно переписывать и переносить постепенно, параллельно занимаясь и продуктовыми задачами.
На старте обновления важно сосредоточиться на тех вещах, которые напрямую влияют на то, как вы пишете код, и которые открывают путь к новым фичам. В нашем случае это было, например, внедрение нового стейт-менеджера. Как только эти базовые блоки обновлены, новые компоненты можно писать уже по современным подходам, а старые переписывать постепенно, по мере необходимости. А такие задачи, как переезд с Webpack на Vite или обновление сборки в целом, можно отложить на потом — они не меняют сам код и не блокируют разработку.
Вопрос, который мне задали на докладе, оказался очень в точку: что делать, если проект стареет быстрее, чем вы его обновляете? Тут важно определить для себя критерии «легаси». Например, если у вас библиотека пятой версии, а недавно вышла шестая — это не значит, что проект мгновенно стал легаси. Но если версия 5 уже три года официально считается устаревшей и реально мешает работе (замедляет сборку или использует подходы, которые давно вышли из употребления, как это было с классами против функциональных компонентов), вот тогда пора действовать.
И напоследок. Если у вас всё же тот самый первый вариант, когда переписывать приходится с нуля, продумайте стратегию постепенного перехода. На одном из проектов мы буквально переписывали его «по страницам». Да, и это проходило не без проблем, но так задачу можно было декомпозировать и оценивать. Параллельно брали продуктовые истории — иногда в новые страницы, иногда даже в старые (компромиссы неизбежны).
Никто не согласится на план «нам нужен год, никакие фичи не делаем, и не факт, что даже уложимся». Любое обновление должно быть разбито на понятные этапы. Так и прогресс виден: не как мифические «0 и вдруг 100%», а постепенно, по шагам. И для команды, и для менеджмента это куда легче и понятнее.
❤8🔥4👍1😁1
Хоть я последнее время и залипаю в Node.js, но трушным фронтендом тоже занимаюсь.
Вот, например, на днях впервые использовала фичу container queries в CSS.
Сценарий: у нас в интерфейсе есть блок, который пользователь может растягивать по ширине — прямо мышкой, за ползунок. А в этом блоке лежит таблица, и в ней хочется скрывать некоторые колонки, если блок слишком узкий.
Обычно мы пишем media-выражения, завязываясь на ширину всего экрана, но тут нужна ширина конкретного компонента. Хвала богам CSS, мы живем в 2025 году, и в наше время есть такая фича, как container queries в CSS.
Как это работает (если вы ещё не успели попробовать)
1. Определяем контейнер (родительский элемент):
2. Пишем запрос (
3. Вы восхитительны!
Самое крутое, что у этой фичи хорошая браузерная поддержка. Значит, можно брать — и делать.
Может, я и не открыла Америку, но как человек, который до сих пор пребывает в лёгком шоке от того, что IE11 умел в grid-ы, я каждый раз радуюсь, когда новые возможности CSS можно использовать на проде. Так что, может и вы порадуетесь сегодня вместе со мной:)
Вот, например, на днях впервые использовала фичу container queries в CSS.
Сценарий: у нас в интерфейсе есть блок, который пользователь может растягивать по ширине — прямо мышкой, за ползунок. А в этом блоке лежит таблица, и в ней хочется скрывать некоторые колонки, если блок слишком узкий.
Обычно мы пишем media-выражения, завязываясь на ширину всего экрана, но тут нужна ширина конкретного компонента. Хвала богам CSS, мы живем в 2025 году, и в наше время есть такая фича, как container queries в CSS.
Как это работает (если вы ещё не успели попробовать)
1. Определяем контейнер (родительский элемент):
.container {
container-type: inline-size;/* Отслеживает ширину */
container-name: my-container;/* Опционально: имя для обращения */
}
2. Пишем запрос (
@container):@container my-container (max-width: 600px) {
.child-element {
font-size: 14px;
}
}
3. Вы восхитительны!
Самое крутое, что у этой фичи хорошая браузерная поддержка. Значит, можно брать — и делать.
Может, я и не открыла Америку, но как человек, который до сих пор пребывает в лёгком шоке от того, что IE11 умел в grid-ы, я каждый раз радуюсь, когда новые возможности CSS можно использовать на проде. Так что, может и вы порадуетесь сегодня вместе со мной:)
❤22🔥10✍2
За последние несколько месяцев в этом канале заметно прибавилось подписчиков (чему я не могу нарадоваться!). Также я экспериментировала с разными форматами — длинные статьи, короткие заметки, даже рассуждения на тему.
Пришло время для небольшого опроса, чтобы откалибровать ваши ожидания от этого канала и мои предпочтения по контенту. Буду признательна, если ответите на следующий вопрос 💫
Пришло время для небольшого опроса, чтобы откалибровать ваши ожидания от этого канала и мои предпочтения по контенту. Буду признательна, если ответите на следующий вопрос 💫
❤8
Вы когда-нибудь задумывались, как работает npx? И что это вообще за инструмент такой?
У меня npx появился в жизни внезапно — я сразу начала его использоваться, а вот что это за покемон и как он работает под капотом, изучить не успела. Знала только, что устанавливать ничего не надо — npx идёт в комплекте с Node.js и npm.
Давайте попробуем немного разобраться сейчас.
Как было раньше
Раньше, чтобы запускать CLI-пакеты (например,
Это добавляло бинарники пакета в системный PATH, но тянуло за собой потенциальные проблемы — например, конфликт версий, если в разных проектах нужна своя версия CLI.
Npx решает эту боль. Он может:
- использовать локально установленный пакет,
- или (если такого нет) скачать временно нужный и сразу запустить.
Без глобальной установки и без добавления в PATH. Плюс, можно запускать конкретные версии одного и того же пакета под разные проекты, не ловя конфликты.
Окей, а что тогда за команда у Vite такая?
Смотрим информацию о команде:
По факту,
И важный момент напоследок
Пакет, который хочется запускать через npx, должен иметь секцию bin в своём package.json. Пример из vite:
Это как раз то, что позволяет вызывать его как CLI-команду.
У меня npx появился в жизни внезапно — я сразу начала его использоваться, а вот что это за покемон и как он работает под капотом, изучить не успела. Знала только, что устанавливать ничего не надо — npx идёт в комплекте с Node.js и npm.
Давайте попробуем немного разобраться сейчас.
Как было раньше
Раньше, чтобы запускать CLI-пакеты (например,
create-react-app) из любого места, их нужно было ставить глобально:npm i -g create-react-app
Это добавляло бинарники пакета в системный PATH, но тянуло за собой потенциальные проблемы — например, конфликт версий, если в разных проектах нужна своя версия CLI.
Npx решает эту боль. Он может:
- использовать локально установленный пакет,
- или (если такого нет) скачать временно нужный и сразу запустить.
Без глобальной установки и без добавления в PATH. Плюс, можно запускать конкретные версии одного и того же пакета под разные проекты, не ловя конфликты.
Окей, а что тогда за команда у Vite такая?
npm create vite@latest my-vue-app -- --template vue
Смотрим информацию о команде:
npm create --help
Create a package.json file
Usage:
npm init <package-spec> (same as `npx create-<package-spec>`)
npm init <@scope> (same as `npx <@scope>/create`)
По факту,
npm create — это синтаксический сахар над npx create-<name>, а под капотом — тот же npx.И важный момент напоследок
Пакет, который хочется запускать через npx, должен иметь секцию bin в своём package.json. Пример из vite:
"bin": {
"create-vite": "index.js",
"cva": "index.js"
}Это как раз то, что позволяет вызывать его как CLI-команду.
1🔥22👍4
Новый цикл статей уже на подходе!)
Мостик между Node.js и браузерным JavaScript — это движок V8. Я попробую разобрать его по кусочкам и заглянуть внутрь: как работает, какие механизмы использует и почему он такой быстрый.
Погружение в V8. Часть 1. История.
Пока цикл ещё не завершён, можно повлиять на его содержание — пишите в комментариях, какие аспекты V8 особенно интересны, и я постараюсь включить их в следующие части 💫
Мостик между Node.js и браузерным JavaScript — это движок V8. Я попробую разобрать его по кусочкам и заглянуть внутрь: как работает, какие механизмы использует и почему он такой быстрый.
Погружение в V8. Часть 1. История.
Пока цикл ещё не завершён, можно повлиять на его содержание — пишите в комментариях, какие аспекты V8 особенно интересны, и я постараюсь включить их в следующие части 💫
3❤13🔥8👍5👏2
Продолжаем разбирать V8 — на этот раз по слоям.
Если первая часть была больше про историю, то теперь спускаемся вглубь: как именно движок исполняет JavaScript, какие компиляторы внутри него живут и зачем их так много.
Ignition, TurboFan, Sparkplug, Maglev — всё это может звучать пугающе, но на самом деле это слоистая архитектура V8, которую я постаралась разложить по полочкам.
Погружение в V8. Часть 2. Из чего состоит движок.
Если первая часть была больше про историю, то теперь спускаемся вглубь: как именно движок исполняет JavaScript, какие компиляторы внутри него живут и зачем их так много.
Ignition, TurboFan, Sparkplug, Maglev — всё это может звучать пугающе, но на самом деле это слоистая архитектура V8, которую я постаралась разложить по полочкам.
Погружение в V8. Часть 2. Из чего состоит движок.
1❤16👍3
Вышла третья часть моего цикла про V8!
На этот раз про то, как V8 разбирает код и что происходит ещё до первого его выполнения. Посмотрим на AST, preparser, сканер, скоупы и байткод.
Погружение в v8. Часть 3. Парсинг, AST и анализ кода.
На этот раз про то, как V8 разбирает код и что происходит ещё до первого его выполнения. Посмотрим на AST, preparser, сканер, скоупы и байткод.
Погружение в v8. Часть 3. Парсинг, AST и анализ кода.
4❤14👍2
Я уже немного писала про Garbage Collection ранее в канале, но цикл про V8 будет неполный без отдельной статьи на эту тему, так что вот:
Погружение в v8. Часть 4. Управление памятью и сборка мусора.
В новой части разбираемся, как движок управляет памятью, оптимизирует сборку мусора и не только.
Погружение в v8. Часть 4. Управление памятью и сборка мусора.
В новой части разбираемся, как движок управляет памятью, оптимизирует сборку мусора и не только.
🔥19❤1
Новая часть цикла про V8 ждёт вас.
И в ней не только изучим теорию некоторых интересных оптимизаций, но и посмотрим на прикладные советы для нашего повседневного JS, которые помогут движку делать свою работу ещё лучше! 🙊
Погружение в v8. Часть 5. Скрытые оптимизации.
И в ней не только изучим теорию некоторых интересных оптимизаций, но и посмотрим на прикладные советы для нашего повседневного JS, которые помогут движку делать свою работу ещё лучше! 🙊
Погружение в v8. Часть 5. Скрытые оптимизации.
🔥14
Финал цикла про V8!
Здесь рассмотрим, как движок взаимодействует с браузером, Node.js и WebAssembly, а также поговорим про будущее.
Погружение в v8. Часть 6. От среды к среде.
Этот цикл был для меня небольшим путешествием внутрь движка.
Надеюсь, читать его было так же интересно, как мне — писать ❤️
Здесь рассмотрим, как движок взаимодействует с браузером, Node.js и WebAssembly, а также поговорим про будущее.
Погружение в v8. Часть 6. От среды к среде.
Этот цикл был для меня небольшим путешествием внутрь движка.
Надеюсь, читать его было так же интересно, как мне — писать ❤️
1❤13🔥4
Интересная тема — как вообще организовывается авторизация в разных проектах.
У кого-то это JWT-токены (тут я когда-то писала про них), у кого-то — сессионные куки, у кого-то и то, и другое.
JWT удобен тем, что сервер выписывает токен, подписывает своим ключом, а клиент просто прикладывает его к каждому запросу. Но если токен утёк, то всё равно до конца его срока жизни он будет валиден — нет никакого механизма отзыва. Поэтому такие токены делают короткоживущими и добавляют второй — refresh-токен, чтобы обновлять сессию.
Дальше начинается самое интересное — где хранить этот refresh-токен. В localStorage небезопасно, в куках — только если httpOnly. А в чистом SPA это уже сложнее, потому что нельзя управлять такими куками с фронта.
Тут кто-то может начать задумываться про Backend-for-Frontend (BFF). Но, как по мне, делать BFF только ради авторизации — странное решение. Это может быть одним из пунктов, но не единственным. Если у вас есть ещё причины (например, хочется проксировать запросы, фильтровать данные или использовать SSR) — тогда да, BFF может дать больше гибкости и безопасности.
В целом, у SPA возможностей в плане авторизации гораздо меньше, чем у фронта с BFF. Поэтому если вы никак не можете менять логику авторизации на бэкенде — BFF может стать неплохим компромиссом.
И ещё важно помнить про блокировку пользователей и отзыв токенов. Даже если JWT живёт неделю, должна быть возможность ограничить доступ человеку, которого заблокировали. Иногда это решается централизованным чёрным списком токенов/сессий, иногда — проверкой статуса при каждом запросе.
Авторизация вообще тесно связана с безопасностью.
Бессмысленно ставить JWT и при этом не защититься от XSS, CSRF и не настроить CSP-политику. Это как поставить стальные ворота, но оставить рядом огромную дыру в стене — мощно, но бесполезно.
Ну и отдельный мир — это SSO (OAuth, OpenID, и вот это всё). Я с ним пока не работала, но тема явно интересная и заслуживает отдельного разбора.
А с чем сталкивались вы? Какие подходы к авторизации вам кажутся удачными, а какие — категорически нет?
У кого-то это JWT-токены (тут я когда-то писала про них), у кого-то — сессионные куки, у кого-то и то, и другое.
JWT удобен тем, что сервер выписывает токен, подписывает своим ключом, а клиент просто прикладывает его к каждому запросу. Но если токен утёк, то всё равно до конца его срока жизни он будет валиден — нет никакого механизма отзыва. Поэтому такие токены делают короткоживущими и добавляют второй — refresh-токен, чтобы обновлять сессию.
Дальше начинается самое интересное — где хранить этот refresh-токен. В localStorage небезопасно, в куках — только если httpOnly. А в чистом SPA это уже сложнее, потому что нельзя управлять такими куками с фронта.
Тут кто-то может начать задумываться про Backend-for-Frontend (BFF). Но, как по мне, делать BFF только ради авторизации — странное решение. Это может быть одним из пунктов, но не единственным. Если у вас есть ещё причины (например, хочется проксировать запросы, фильтровать данные или использовать SSR) — тогда да, BFF может дать больше гибкости и безопасности.
В целом, у SPA возможностей в плане авторизации гораздо меньше, чем у фронта с BFF. Поэтому если вы никак не можете менять логику авторизации на бэкенде — BFF может стать неплохим компромиссом.
И ещё важно помнить про блокировку пользователей и отзыв токенов. Даже если JWT живёт неделю, должна быть возможность ограничить доступ человеку, которого заблокировали. Иногда это решается централизованным чёрным списком токенов/сессий, иногда — проверкой статуса при каждом запросе.
Авторизация вообще тесно связана с безопасностью.
Бессмысленно ставить JWT и при этом не защититься от XSS, CSRF и не настроить CSP-политику. Это как поставить стальные ворота, но оставить рядом огромную дыру в стене — мощно, но бесполезно.
Ну и отдельный мир — это SSO (OAuth, OpenID, и вот это всё). Я с ним пока не работала, но тема явно интересная и заслуживает отдельного разбора.
А с чем сталкивались вы? Какие подходы к авторизации вам кажутся удачными, а какие — категорически нет?
🤔6❤3
Кстати, уже завтра я буду выступать на FrontendConf с докладом про нативные модули и node-gyp. Покажу разные интересные графики, и пообсуждаем целесообразность использования такого подхода в разработке на Node.js 💫
frontendconf.ru
Анастасия Котова на FrontendConf 2025
Node.js умеет многое, но не все. Когда нужно выжать максимум из вычислений или достучаться до «железа», на сцену выходят нативные модули. Node-gyp — не самая популярная технология, но именно она позволяет быстро подключить мощь C++ к Node.js и заметно ускорить…
❤12🔥6
Node.js на стероидах.pdf
12.7 MB
Вчера выступила с докладом про нативные модули (или native addons) в Node.js. Это расширения, написанные на C/C++, которые обеспечивают доступ к высокопроизводительным или низкоуровневым функциям, недоступным на чистом JavaScript.
По традиции, делюсь ссылкой на полезные материалы и приклыдываю свои слайды:
👉 Материалы на github
(в презентации много графиков с бенчмарками, а в материалах исходный код для них)
Если у вас есть вопросы по этой теме — пишите мне в личку @startpoint_forl, в сообщения этого канала или в комментарии под этим постом.
Также можете просто поставить реакцию, мне будет очень приятно)
По традиции, делюсь ссылкой на полезные материалы и приклыдываю свои слайды:
👉 Материалы на github
(в презентации много графиков с бенчмарками, а в материалах исходный код для них)
Если у вас есть вопросы по этой теме — пишите мне в личку @startpoint_forl, в сообщения этого канала или в комментарии под этим постом.
Также можете просто поставить реакцию, мне будет очень приятно)
❤26🔥13
А теперь — пост про то, что не влезло в доклад о нативных модулях: связь Node.js и C++, обработку исключений внутри модулей, команды для компиляции и работу с памятью.
Ещё немного про нативные модули в Node.js
Ну а я уже думаю над темами следующих интересных статей и докладов для вас. Будем копать глубже!)
Ещё немного про нативные модули в Node.js
Ну а я уже думаю над темами следующих интересных статей и докладов для вас. Будем копать глубже!)
Telegraph
Ещё немного про нативные модули в Node.js
Введение На прошлой неделе я выступала с докладом о нативных модулях Node.js — как они устроены, зачем нужны и в каких случаях стоит использовать C++ рядом с JavaScript, а в каких нет. Материалы доклада можно посмотреть в этом посте. А здесь мне хочется чуть…
🔥5❤2
В одной из частей цикла про V8 я рассказывала, почему важно сохранять массивы однородными и без «дыр» — тогда движок может их эффективнее оптимизировать.
В блоге V8 есть отличная статья, где показано, как можно посмотреть, какой тип элементов сейчас у массива и от чего он меняется. Ниже — краткий гайд, как повторить это у себя локально.
Нам понадобится отладочная (debug) сборка V8 — с ней можно смотреть не только на типы элементов, но и, например, как движок оптимизирует или деоптимизирует код.
1. Сначала ставим depot_tools, чтобы получить утилиту
2. Потом по инструкции из документации подтягиваем исходники V8.
На macOS важно: если у вас установлены только XCode Command Line Tools, их нужно удалить и поставить полноценный XCode. Подробности — здесь.
3. Дальше собираем движок:
У меня сборка шла очень долго, поэтому лучше сразу собирать правильную версию (release или debug). Debug-версия обладает бОльшими возможностями для логирования разной информации.
После сборки можно запустить движок в REPL-режиме:
Флаг
Пример вывода:
Можно и просто передать файл с кодом:
А если добавить флаг
Результат:
Дальше можно экспериментировать: добавлять в массив
В блоге V8 есть отличная статья, где показано, как можно посмотреть, какой тип элементов сейчас у массива и от чего он меняется. Ниже — краткий гайд, как повторить это у себя локально.
Нам понадобится отладочная (debug) сборка V8 — с ней можно смотреть не только на типы элементов, но и, например, как движок оптимизирует или деоптимизирует код.
1. Сначала ставим depot_tools, чтобы получить утилиту
gclient.2. Потом по инструкции из документации подтягиваем исходники V8.
На macOS важно: если у вас установлены только XCode Command Line Tools, их нужно удалить и поставить полноценный XCode. Подробности — здесь.
3. Дальше собираем движок:
gclient sync
cd /path/to/v8
git pull && gclient sync
tools/dev/gm.py arm64.debug # debug-сборка для arm на macOS
У меня сборка шла очень долго, поэтому лучше сразу собирать правильную версию (release или debug). Debug-версия обладает бОльшими возможностями для логирования разной информации.
После сборки можно запустить движок в REPL-режиме:
v8/out/arm64.debug/d8 --allow-natives-syntax
Флаг
--allow-natives-syntax позволяет использовать специальные отладочные функции, такие как %DebugPrint(array):
d8> const array = [1, 2, 3]; %DebugPrint(array);
Пример вывода:
DebugPrint: 0x2dcc00389c0d: [JSArray]
- map: 0x2dcc0005b7d1 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties]
- prototype: 0x2dcc0005b7f9 <JSArray[0]>
- elements: 0x2dcc0006ca25 <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)]
- length: 3
- properties: 0x2dcc000007bd <FixedArray[0]>
.....
Можно и просто передать файл с кодом:
v8/out/arm64.debug/d8 --allow-natives-syntax ~/Documents/all-examples/v8/test.js
А если добавить флаг
--trace-elements-transitions, то движок будет печатать все изменения типа:
// test2.js
const array = [1, 2, 3];
array[3] = 4.56;
v8/out/arm64.debug/d8 --trace-elements-transitions ~/Documents/all-examples/v8/test2.js
Результат:
elements transition [PACKED_SMI_ELEMENTS -> PACKED_DOUBLE_ELEMENTS] in ~+15 at test2.js:1 for 0x2cf600389c45 <JSArray[3]> from 0x2cf60006ca0d <FixedArray[3]> to 0x2cf600389c55 <FixedDoubleArray[22]>
Дальше можно экспериментировать: добавлять в массив
undefined, -0, пропущенные индексы — и смотреть, как V8 сразу меняет внутренний тип. Это наглядный способ понять, как движок анализирует наш код и почему иногда одно лишнее значение или неправильная инициализация может замедлить выполнение.👍11🔥5
Как можно профилировать память в Node.js?
Один из базовых способов — heap snapshot через Chrome DevTools. Для этого нужно запустить Node с флагом --inspect:
После запуска можно открыть в браузере
Если же мы хотим отслеживать метрики памяти в реальном времени, то можно сделать это с помощью PerformanceObserver. Он слушает события, создаваемые системой perf_hooks. Например, можно смотреть, как растёт heap и когда происходят сборки мусора:
Если нужно больше деталей о работе V8 и нет времени писать лишний код, можно просто запустить процесс с флагом --trace_gc:
В консоли появятся строки вроде:
Здесь видно тип сборки мусора, её длительность и изменение размера кучи.
Ну а самый простой и быстрый способ получить обзор текущего состояния, и, скорей всего, вы про него уже не раз слышали — метод process.memoryUsage. Он возвращает данные по основным сегментам памяти:
Один из базовых способов — heap snapshot через Chrome DevTools. Для этого нужно запустить Node с флагом --inspect:
node --inspect app.js.После запуска можно открыть в браузере
chrome://inspect и подключиться к процессу в DevTools и на вкладке Memory снять снимок кучи. Он показывает, какие объекты занимают память.Если же мы хотим отслеживать метрики памяти в реальном времени, то можно сделать это с помощью PerformanceObserver. Он слушает события, создаваемые системой perf_hooks. Например, можно смотреть, как растёт heap и когда происходят сборки мусора:
import { PerformanceObserver, performance } from 'node:perf_hooks';
const obs = new PerformanceObserver((items) => {
for (const entry of items.getEntries()) {
console.log(`[${entry.entryType}]`, entry.name, entry.duration.toFixed(2), 'ms');
}
});
obs.observe({ entryTypes: ['gc'] });
Если нужно больше деталей о работе V8 и нет времени писать лишний код, можно просто запустить процесс с флагом --trace_gc:
node --trace_gc app.js.В консоли появятся строки вроде:
[89452:0xa81400000] 3103 ms: Scavenge 18.9 (27.7) -> 18.7 (50.7) MB, pooled: 0 MB, 4.29 / 0.00 ms (average mu = 1.000, current mu = 1.000) allocation failure;
Здесь видно тип сборки мусора, её длительность и изменение размера кучи.
Ну а самый простой и быстрый способ получить обзор текущего состояния, и, скорей всего, вы про него уже не раз слышали — метод process.memoryUsage. Он возвращает данные по основным сегментам памяти:
const mem = process.memoryUsage();
console.log(`Heap used: ${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB`);
console.log(`RSS: ${(mem.rss / 1024 / 1024).toFixed(2)} MB\n`);
👍5❤2