Redux FAQ: Производительность

Содержание

Производительность

Насколько хорошо “масштабируется” Redux с точки зрения производительности и архитектуры?

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

Работа Redux как правило, делится на несколько частей:

  • обработка действие в миддлвэрах и редюсерах (включая дублирование объекта для постоянных обновлений),
  • уведомление подписчиков после отправки действий,
  • обновление UI-компонентов на основе изменения состояния.

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

Redux может быть не так эффективен из коробки, по сравнению с другими библиотеками. Для максимальной производительности отрисовки в React-приложении, состояние должно храниться в нормализованной форме, множество компонентов должны подключаться к одному хранилищу, а не к нескольким, и подключенный список компонентов должен передавать идентификатор каждого элемента своим подключенным потомкам (позволяя тем самым элементам списка искать их собственные данные по ID). Это минимализирует общее количество перерисовок. Использование мемоизированных функций также является важным фактором эффективности.

С точки зрения архитектуры, неофициальные данные показывают, что Redux хорошо работает с различными проектами и размерами команды. В настоящее время Redux используется сотнями компаний и тысячами разработчиков, имеет несколько сотен тысяч ежемесячных установок из NPM. Один разработчик сообщил:

для сравнения, у нас есть ~500 типов действий, ~400 редюсеров, ~150 компонентов, 5 миддлвэров, ~200 действий, ~2300 тестов

Дополнительная информация

Документация

Статьи

Обсуждения

Не будет ли вызов “всех моих редюсеров” для каждого действия медленным?

Важно иметь ввиду, что Redux-хранилище на самом деле имеет всего одну функцию-редюсер. Хранилище передает текующее состояние и отправленное действие этому единственному редюсеру и позволяет ему обрабатывать это все как надо.

Очевидно, попытка обрабатывать каждое возможное действие в одной функции плохо масштабируется, хотя бы с точки зрения размера функции и читабельности. Таким образом, есть смысл разделить реальную работу на отдельные функции, которые могут быть вызваны редюсером верхнего порядка. В частности, общий рекомендуемый подход — это иметь отдельную функцию (подредюсер), которая ответственна за управление обновлениями на определенном участке состояния в определенном ключе. Функция combineReducers(), поставляемая с Redux, — 1 из множества способов реализации этого подхода. Также настоятельно рекомендуется держать состояние хранилища единообразным и нормализированным на столько, на сколько это возможно. В конечном счете, только Вы отвечаете за организацию логики Вашего редюсера любыми способами, какими только пожелаете.

Однако, даже если у Вас много различных редюсеров, объединенных вместе, даже с глубоко вложенным состоянием, скорость редюсера вряд ли будет проблемой. Движки JavaScript способны запускать очень большое количество вызовов функций в секунду, а большинство Ваших редюсеров вероятнее всего используют конструкцию switch и возвращают существующее состояние по умолчанию в ответ на большинство действий.

Если вы действительно обеспокоены производительностью редюсера, вы можете использовать такие утилиты, как redux-ignore или reduxr-scoped-reducer, чтоб гарантировать, что только определенные редюсеры прослушивают конкретные действия. Также Вы можете использовать redux-log-slow-reducers, чтобы провести сравнительный анализ эффективности.

Дополнительная информация

Обсуждения

Должен ли я иметь полноценный клон моего состояния в редюсере? Не будет ли копирование моего состояния медленным?

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

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

Распростораненное заблуждение Redux: Вам надо полноценно клонировать состояние. На самом деле: если внутри ничего не меняется, достаточно хранить ссылку!

Дополнительная информация

Документация

Обсуждения

Как мне уменьшить количество событий обновления хранилища?

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

Если Вы используете React, помните, что Вы можете улучшить производительность нескольких синхронных отправок обертыванием их в ReactDOM.unstable_batchedUpdates(), но этот API экспериментален и может быть удален в любом выпуске React, поэтому не полагайтесь на это слишком сильно. Взгляните на аналоги:

  • redux-batched-actions — редюсер высокого порядка, который позволяет Вам отправлять несколько действий так, будто это одно действие, и “распаковывать” их в редюсере,
  • redux-batched-subscribe — расширитель хранилища, который позволяет Вам вызывать подписчиков для множественных отправок не чаще, чем раз в определенное время (debounce),
  • redux-batch — расширитель хранилища, которых обрабатывает отправку набора действий с уведомлением одного подписчика.

Дополнительная информация

Обсуждения

Libraries

Будут ли проблемы с памятью из-за использования “одного дерева состояния”? Будет ли вызов большого количества действий занимать память?

Во первых, с точки зрения использования ресурсов памяти, Redux не сильно отличается от других JavaScript-библиотек. Единственно отличие — все возможные ссылки на объекты вместе вложены в одно дерево, а не хранятся в различных независимах экземплярах модели, как например в Backbone.

Во-вторых, типичное Redux-приложение, вероятно, отчасти меньше использует память, чем такое же Backbone-приложение, из-за того, что Redux поощряет использование простых JavaScript-объектов и массивов вместо создания экземпляров моделей и коллекций.

Наконец, Redux держит в памяти в один момент времени только одно дерево состояния со ссылками. Объекты, которые больше не имеют ссылок в этом дереве, обычно будут собраны сборщиком мусора.

Redux сам не хранит историю действий. Однако, Redux DevTools — хранит, таким образом действия могут быть проиграны заново, но это возможно только в процессе разработки и не используется в продакшн-версии.

Дополнительная информация

Документация

Обсуждения

results matching ""

    No results matching ""