30 марта 2022 года команда инженеров Meta анонсировали новую версию React Native 0.68. Помимо различных минорных улучшений и фиксов эта версия содержит историческое для платформы изменение, впервые мы можем попробовать в своих приложениях так называемую новую архитектуру. Давайте вместе разберемся что за новая архитектура и почему к ней шли без малого 4 года.

Как устроен React Native

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

За сборку приложения отвечают следующие модули:

  • BUCK - мультиплатформенная система сборки

  • Metro bundler - сборщик JS написаный специально для React Native

  • React Native CLI - набор утилит для сборки приложения под конкретную платформу

Во время выполнения обязательными являются:

  • JS Core или Hermes - движки на которых запускается JS код

  • Yoga layout - кросс платформенный менеджер компоновки с синтаксисом близки к css flex box

  • ReactJS и React Native - ядро приложения, отвечают за рендеринг на стороне JS и взаимодействие с нативным слоем

И так мы собрали RN приложение. Что же происходит под капотом?

Архитектура RN основанная на использовании Bridge
Архитектура RN основанная на использовании Bridge
  1. Пользователь нажимает на иконку приложения

  2. Native Thread загружаешь все нативные зависимости и модули

  3. Native Thread стартует JS Thread который загружает собраный js bundle

  4. JS Thread посылает сериализованное сообщение через Bridge о том как отрисовать UI на нативной стороне.

  5. Shadow Thread получает эти сообщения и формирует UI Tree

  6. На базе UI Tree менеджер компоновки Yoga формирует нативные компоненты с размерами для конкретной платформы и устройства и передает на отрисовку в Native Thread

  7. Native Thread отрисовывает компоненты на экране. Ниже приведен пример мэпинга RN компонентов на компоненты специфичные различным платформам

Взаимодействие с пользователем происходит по такой же схеме, Native Thread отвечает за обработку жестов и отправляет информацию о событии через Bridge на JS Thread где происходит расчет нового состояния UI и повторяются шаги 4-7.

Проблемы старой архитектуры

В 2018 году команда RN объявила о начале большой работы по созданию новой архитектуры. Основной проблемой виделся асинхронный Bridge

  • большое количество событий проходящих через Bridge и требующих сериализации/десериализации может послужить бутылочным горлышком и вызывать медлительность UI

  • асинхронная природа Bridge не позволяет использовать его с синхронными нативными компонентами эффективно

  • так как коммуникация между Native и JS происходит через сообщение, JS не может эффективно управлять Shadow Thread напрямую так как Shadow Thread ничего не знает о структурах данных на стороне JS

Новая архитектура

Схематично новая архитектура выглядит так

Вы наверное заметили множество новых названий, давайте рассмотрим каждое из них.

JSI - JavaScript Interface замена для Bridge. С помощью JSI можно напрямую взаимодействовать с нативными модулями избегая накладных расходов на пересылку сообщений. Через JSI нативные методы будут доступны для JavaScript через хост-объекты C++. Эти хост объекты могут содержать как самостоятельную функциональность на C++ так и выступать посредниками для взаимодействия с нативной платформой, например на Objective-c или Java через JNI. Важно что методы JSI могут быть как синхронными так и асинхронными.

Fabric - новая система рендеринга пришедшая на замену UIManager. Благодаря JSI теперь не нужно держать копию дерева компонентов на JS и Shadow thread и синхронизировать ее через Bridge а можно манипулировать этим деревом напрямую. Fabric делает работу с UI синхронной а так же приоритизирует UI задачи над асинхронными вызовами, например HTTP запросы или IO операции.

Turbo Modules - в текущей архитектуре все модули для работы с нативной функциональностью (Bluetooth, Geo, Camera и т.д.) должны быть загружены во время старта приложения. На практике это значительно замедляет время старта приложения. Turbo Modules устраняют эту проблему и позволяют загружать нативные модули тогда когда они нужны в приложении. Еще одним преимуществом является использование JSI для коммуникации между модулем и JS.

CodeGen - упрощает создание нативных интерфейсов для работы с Turbo Modules и Fabric. С помощью Flow или TypeScript разработчик модуля описывает его интерфейс а С++ код будет сгенерирован автоматически.

Теперь в новой схеме JS Thread намного сильнее интегрирован в разные процессы напрямую, можно параллельно общаться с несколькими модулями не дожидаясь ответа в виде сообщения через Bridge как было раньше.

Более детально почитать про то как работает новый рендеринг можно на сайте React Native в специальном разделе.

Как использовать на практике?

На практике для поддержки новой архитектуры мы должны обеспечить работоспособность всех нативных модулей.

Внутри React Native все компоненты уже поддерживают новую архитектуру и если вы собираетесь создать новое приложение или же просто хотите экспериментировать с новой архитектурой то эта инструкция будет полезна.

Если вы являетесь разработчиком RN библиотек или у вас есть свои нативные модули то следуя этой инструкции вы сможете адаптировать свою библиотеку. Хорошим примером реализации новой архитектуры могут служить следующие библиотеки:

  • react-native-screens - с обзором pull requests которые были сделаны для поддержки новой архитектуры

  • react-native-mmkv - использует JSI для быстрого доступа к MMKV хранилищу написанному на С++

  • React Native New Architecture Sample - репозиторий с пошаговым объяснением как мигрировать вашу библиотеку на новую архитектуру

А что с уже существующими приложениями? По моим ощущениям потребуется еще от 6 до 12 месяцев для того чтобы разработчики библиотек адаптировали их под новую архитектуру. Однозначно можно сказать одно - новая архитектура эта та реальность в которой мы уже находимся. Не игнорируйте ее, помогайте сообществу, экспериментируйте и это положительно скажется как на вашем проекте так и на вашем опыте работы с React Native.

Полезные материалы

Комментарии (3)


  1. Mox
    02.05.2022 21:46

    Очень долго пилили, я уже к концу 2020 был готов похоронить React Native, да и сейчас думаю слив RN Flutterу связан именно с тем что так долго это все релизили.


    1. kirill3333 Автор
      02.05.2022 21:57

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


  1. andreyverbin
    03.05.2022 01:37

    Авторов RN нужно было сразу уволить. То, что асинхронный bridge это провал было ясно сразу же. Был Appcelerator Titanium с теми же проблемами и с тем же результатом - сдох. Они просто не удосужились проверить свои идеи. Кроме того, асинхронно обрабатывать скроллинг это же верх идиотизма. Максимум нажатия на кнопку, что резко ограничивает применение, но об этом же никто не говорил.