Главная / Статьи / Нитро-модули: почему статические привязки превосходят TurboModules в React Native

Нитро-модули: почему статические привязки превосходят TurboModules в React Native

Объясняется, как модули Nitro используют заранее скомпилированные статические связи вместо динамического поиска, что позволяет им значительно превосходить TurboModules и Expo Modules в React Native.

1178 слов

TurboModules должны были стать решением проблемы. Они заменили устаревшую архитектуру моста, устранили ненужную нагрузку и стали общепринятым подходом к написанию нативного кода, взаимодействующего с JavaScript. Затем появилась более новая библиотека под названием Nitro Modules, которая сделала это «окончательное решение» устаревшим.

Результаты опубликованных тестов показывают, что при тестировании одинаковых синхронных вызовов функций Nitro Modules могут превзойти Expo Modules в производительности вплоть до 59 раз, а TurboModules — примерно в 15 раз. Даже при работе с строками, которые обычно увеличивают нагрузку при переходе между JavaScript и нативным кодом, Nitro сохраняет преимущество в 5–13 раз. При передаче более крупных объемов данных, таких как изображения или необработанные буферы, Nitro демонстрирует дополнительное улучшение на 8–40 процентов благодаря подходу без копирования данных, который исключает их дублирование в памяти.

Такие цифры требуют объяснения. Что именно делает Nitro внутри, и почему такой дизайн не появился раньше?

Проблема, которую никто другой не смог решить

Nitro был создан не как инструмент для тестирования производительности. Он возник в результате работы Marc Rousavy, создателя VisionCamera, в ответ на очень конкретное ограничение: ни TurboModules, ни Expo Modules не могли должным образом обрабатывать кадры.

В VisionCamera один кадр камеры можно рассматривать как буфер объемом около 10 мегабайт. Этот буфер невозможно скопировать через мост связи, даже с использованием TurboModules, и он также не вписывается в обычную структуру вида JSON. На самом деле Rousavy нужен был способ передачи сложного, имеющего состояние нативного объекта, написанного на C++ или Swift, непосредственно в JavaScript, включая все его методы и свойства. У TurboModules не было механизма для работы с такими объектами.

Nitro был создан именно для того, чтобы сделать это возможным, причем значительное увеличение скорости оказалось дополнительным преимуществом, привлекшим гораздо больше внимания, чем первоначальная проблема, которую он решал.

Одно архитектурное решение

Настоящая разница между TurboModules и Nitro сводится к одному дизайнерскому решению: к тому, как каждая система представляет нативный объект после его появления в движке JavaScript.

TurboModules опираются на jsi::HostObject. Каждый раз, когда код JavaScript обращается к свойству или вызывает метод одного из этих объектов, движок должен динамически решать это обращение прямо в момент вызова. Эта проверка происходит при каждом вызове, и эти постоянные затраты быстро накапливаются у модулей, которые вызываются часто.

Nitro использует другой подход, применяя jsi::NativeState. В сочетании с инструментом генерации кода под названием Nitrogen он заранее генерирует все необходимые биндинги для C++, Swift или Kotlin ещё до запуска приложения. Ничто не решается динамически во время выполнения. Преобразование между JavaScript и нативными типами выполняется статически заранее, что означает, что вызов модуля Nitro ведёт себя скорее как обычный вызов функции, чем как использование механизма динамического поиска во время выполнения.

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

В Nitro любой нативный объект, написанный на C++, Swift или Kotlin, называется гибридным объектом. Nitrogen анализирует определение интерфейса на TypeScript и автоматически генерирует код, необходимый для передачи такого объекта через границу между JS и нативными средами, включая обработку перечислений, объединений и структур. Именно эти инструменты позволили Rousavy предоставить что-то настолько нестандартное, как кадр от живой камеры, без необходимости вручную писать отдельный мостовой код для каждой из трех платформ.

Почему это выходит за рамки простой библиотеки

VisionCamera стал первым доказательством эффективности данного подхода, но конструкция Nitro изначально не предназначалась для того, чтобы оставаться единственным решением для одного конкретного случая использования. Его архитектура обеспечивает любому нативному модулю встроенную поддержку массивных буферов, состояний нативных объектов и прямой взаимодействия с C++, что при предыдущих подходах было либо крайне неудобно, либо совершенно невозможно.

Более широкая экосистема React Native начинает обращать на это внимание. Проекты вроде react-native-nitro-cache, а также инструменты для кэширования изображений, обработки задач машинного обучения и работы с игровыми движками перестраиваются на основе Nitro именно для снижения нагрузки при преобразовании кода JavaScript в код нативного уровня в тех сферах, где производительность имеет наибольшее значение. Это отражает более общую тенденцию в React Native, когда основные библиотеки реструктурируются с учётом новой архитектуры, а не рассматриваются как что-то, что можно внедрить позже. Использование Nitro всё ещё значительно отстает от TurboModules, который по-прежнему остаётся стандартным выбором для большинства библиотек, но тенденция очевидна. Там, где первостепенной является чистая производительность, Nitro всё чаще становится первым инструментом, к которому обращаются разработчики.

Что это означает для авторов нативных модулей

Если вы в настоящее время используете модуль нативного типа, этот сдвиг заслуживает вашего внимания. TurboModules не исчезнут в ближайшее время, и для простых модулей разница в производительности, скорее всего, не будет заметна для конечных пользователей. Однако если ваш модуль связан с чем-либо, чувствительным к производительности, высокой частотой вызовов, большими объемами данных или объектами, которые нельзя легко преобразовать в JSON, Nitro сейчас, скорее всего, является более надежной основой для разработки.

Решение начать разработку совершенно нового нативного модуля в TurboModules в 2026 году фактически означает работу в архитектуре, которую уже превзошла более быстрая и продолжающая развиваться альтернатива. Генератор кода Nitro автоматически выполняет гораздо больше повторяющихся задач одновременно на всех трех платформах, в результате чего получаемый продукт работает быстрее при меньшей необходимости в ручном написании нативного кода для его поддержки. Для команд, уже использующих TurboModule, миграция — это не просто вопрос включения соответствующего параметра, но те же самые результаты тестирования, которые делают Nitro привлекательным решением, также являются убедительными аргументами в пользу проведения этой миграции как можно скорее.

React Native уже пережил несколько настоящих архитектурных поворотных моментов: отказ от старой архитектуры, введение новой архитектуры и теперь этот. Nitro появился не благодаря официальному поручению от Meta. Он появился потому, что одному разработчику понадобилась функциональность, которую TurboModules просто не могли обеспечить; он создал решение публично и позволил полученным результатам тестов говорить сами за себя.

Связанные статьи

  • React 19.2: подробное руководство — компонент Activity, хук useEffectEvent и статическая отрисовка — Узнайте, как новый компонент Activity, хук useEffectEvent и возможность частичной статической отрисовки в React 19.2 устраняют скрытые проблемы с производительностью в современных интерфейсах.
  • Почему уход Shopify от React Native не угрожает Expo — Объясняется, почему переход Shopify с React Native на нативные технологии Swift и Kotlin не означает конца разработки кроссплатформенных приложений с использованием Expo для большинства команд.
  • Создание надежного читера PDF для больших документов в React Native — Ознакомьтесь с архитектурой для отображения огромных PDF-файлов из нескольких тысяч страниц в React Native, включая механизмы отложенной обработки закладок, поиска и стабильного навигирования на устройствах с ограниченными ресурсами.
  • Утечки памяти в React Native: отслеживание стека JS и владельцев нативной памяти — Узнайте, почему сбор мусора не может спасти приложение React Native от утечек нативной памяти, и как выяснить, что препятствует завершению работы обратных вызовов, объектов JSI и декодированных изображений.
  • Почему Codegen делает подход «сначала спецификация» обязательным для React Native TurboModules — Узнайте, как Codegen преобразует спецификацию TurboModule на TypeScript в контракт времени сборки, что происходит при её игнорировании и где действие этого правила прекращается.