RAM модули и встроенные запросы¶
Если у вас большое приложение, возможно, вам стоит рассмотреть формат пакета модулей случайного доступа (RAM) и использование встроенных требований. Это полезно для приложений с большим количеством экранов, которые, возможно, никогда не будут открыты во время обычного использования приложения. В целом это полезно для приложений, содержащих большое количество кода, который не нужен в течение некоторого времени после запуска. Например, приложение включает сложные экраны профиля или менее используемые функции, но в большинстве сеансов используется только главный экран приложения для получения обновлений. Мы можем оптимизировать загрузку пакета, используя формат RAM и требуя эти функции и экраны в режиме inline (когда они действительно используются).
Загрузка JavaScript¶
Прежде чем react-native сможет выполнить JS-код, этот код должен быть загружен в память и разобран. При использовании стандартного пакета, если вы загружаете пакет размером 50мб, все 50мб должны быть загружены и разобраны, прежде чем любой из них может быть выполнен. Оптимизация RAM-пакетов заключается в том, что вы можете загрузить только ту часть из 50 мб, которая вам действительно нужна при запуске, и постепенно загружать все большую часть пакета по мере необходимости этих разделов.
Inline Requires¶
Inline require откладывает требование модуля или файла до тех пор, пока этот файл действительно не понадобится. Базовый пример выглядит следующим образом:
VeryExpensive.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Optimized.tsx | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Даже без формата RAM встроенные require
могут привести к улучшению времени запуска, поскольку код в VeryExpensive.js
будет выполняться только после того, как он впервые потребуется.
Включить формат RAM¶
На iOS использование формата RAM создаст единый индексированный файл, который react native будет загружать по одному модулю за раз. На Android по умолчанию будет создаваться набор файлов для каждого модуля. Вы можете заставить Android создавать один файл, как и iOS, но использование нескольких файлов может быть более производительным и требует меньше памяти.
Включите формат RAM в Xcode, отредактировав этап сборки "Bundle React Native code and images". Перед ../node_modules/react-native/scripts/react-native-xcode.sh
добавьте export BUNDLE_COMMAND="ram-bundle"
:
1 2 3 |
|
На Android включите формат RAM, отредактировав файл android/app/build.gradle
. Перед строкой apply from: "../../node_modules/react-native/react.gradle"
добавьте или измените блок project.ext.react
:
1 2 3 |
|
Используйте следующие строки на Android, если вы хотите использовать один индексированный файл:
1 2 3 4 |
|
Если вы используете Hermes JS Engine, вам не следует включать функцию RAM bundles. В Hermes, при загрузке байткода, mmap
гарантирует, что весь файл не будет загружен. Использование Hermes с RAM bundles может привести к проблемам, поскольку эти механизмы несовместимы друг с другом.
Настройка предварительной загрузки и встроенных требований¶
Теперь, когда у нас есть RAM-бандл, вызов require
становится накладным. Теперь require
должен посылать сообщение через мост, когда он встречает модуль, который еще не загружен. Это больше всего повлияет на запуск, потому что именно в этот момент происходит наибольшее количество вызовов require, пока приложение загружает начальный модуль. К счастью, мы можем настроить часть модулей на предварительную загрузку. Чтобы сделать это, вам нужно будет реализовать некоторую форму inline require.
Исследование загруженных модулей¶
В корневой файл (index.(ios|android).js
) после начального импорта можно добавить следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Когда вы запустите свое приложение, вы можете посмотреть в консоли, сколько модулей было загружено, а сколько ожидает загрузки. Возможно, вы захотите прочитать имена модулей и посмотреть, нет ли сюрпризов. Обратите внимание, что встроенные require вызываются при первом обращении к импорту. Вам может потребоваться исследование и рефакторинг, чтобы гарантировать, что при запуске будут загружаться только нужные вам модули. Обратите внимание, что вы можете изменить объект Systrace на require, чтобы помочь отладить проблемные require.
1 2 3 4 5 |
|
Все приложения разные, но, возможно, имеет смысл загружать только те модули, которые нужны для самого первого экрана. Когда вы будете удовлетворены, поместите вывод загруженных имен модулей в файл с именем packager/modulePaths.js
.
Обновление metro.config.js¶
Теперь нам нужно обновить metro.config.js
в корне проекта, чтобы использовать наш только что созданный файл modulePaths.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Запись preloadedModules
в конфигурации указывает, какие модули должны быть помечены как предварительно загруженные при сборке пакета RAM. Когда пакет загружается, эти модули загружаются немедленно, еще до выполнения каких-либо требований. Запись blockList
указывает на то, что эти модули не должны требоваться в строке. Поскольку они загружены заранее, использование встроенного require не дает никакого преимущества в производительности. Фактически, сгенерированный JavaScript тратит дополнительное время на разрешение встроенного require каждый раз, когда ссылается на импорт.
Тестирование и измерение улучшений¶
Теперь вы должны быть готовы к созданию приложения с использованием формата RAM и встроенных требований. Убедитесь, что вы измерили время до и после запуска.