Предотвращение утечек памяти в приложениях React Native

Все больше и больше компаний-разработчиков программного обеспечения прибегают к React native для разработки своих собственных приложений. Общий код можно использовать для разработки кроссплатформенных приложений. Но, как мы знаем, у каждого программного обеспечения есть свои минусы и плюсы, как и у React-native. Утечки памяти - одна из основных проблем для любого языка программного обеспечения, и это одна из самых сложных вещей, которые разработчик может выяснить, чтобы выяснить первопричину утечек памяти.

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

1) Освобождение слушателей или таймеров, добавленных во время монтирования компонента.

Это одна из основных и частых ошибок, которые делает большинство разработчиков при написании кода. Давайте рассмотрим пример для лучшего понимания:

В приведенном выше фрагменте кода все выглядит идеально. Здесь мы зарегистрировали слушателей для KeybaordDidShow и KeyboardDidHide во время монтирования компонента и сохранения текущего состояния клавиатуры в переменной состояния. Поскольку мы никогда не удаляем эти прослушиватели, они все равно будут получать события клавиатуры даже после размонтирования компонента. В то же время модуль Keyboard будет иметь список активных слушателей в глобальной области видимости - как и в нашем случае, он сохранит функции стрелок, которые мы передаем методу addListener. В свою очередь, эти стрелочные функции сохраняют это - то есть ссылку на компонент MainPage, который, в свою очередь, ссылается на свои свойства через this.props, свои дочерние элементы через this.props.children, дочерние элементы своих дочерних элементов и т. Д. Эта простая ошибка может привести к очень большие области памяти остались сохраненными случайно.

Вышеупомянутая проблема может быть решена путем отмены регистрации слушателей при отключении компонента.

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

2) Утечки области видимости закрытия
Утечки области видимости закрытия - одна из самых сложных вещей, которых нужно избежать при написании кода, но она может

быть подавленным, помня о нескольких вещах.

Объект, содержащий все переменные вне области действия замыкания, на которые имеется ссылка из этого замыкания, называется объектом замыкания.

Чтобы понять это, давайте рассмотрим пример реализации таймера обратного отсчета. Для этого мы возьмем начальное время как props и сохраним текущее время, оставшееся в его состоянии. Для обновления таймера мы будем использовать setInterval, пока компоненты монтируются, то есть ComponentDidMount.

Здесь, в componentDidMount, мы создали экземпляр стрелочной функции (закрытие), которая обновит состояние. Чтобы стрелочная функция работала, должны быть некоторые переменные из области, в которой определена функция, а именно часы, минуты, секунды и this (поскольку она использует this.setState или this._interval). В виртуальной машине Javascript экземпляр стрелочной функции представлен как объект, который сохраняет ссылки на все переменные, которые он «захватывает». Обратите внимание, что переменная обратного отсчета также определена в той же области, что и функция стрелки, но, поскольку она не «захватывается» стрелкой, она не будет сохранена функцией.

Теперь предположим, что мы хотим обработать обновление реквизита, например, в этом случае для сброса значений обратного отсчета будут переданы новые реквизиты, и для этого мы будем использовать метод жизненного цикла ComponentDidUpdate. Если какой-либо из реквизитов, связанных с обратным отсчетом, таких как обратный отсчет, часы, минуты или секунды, изменится, мы перезапустим обратный вызов интервала:

Однако мы используем тот же код в ComponentDidUpdate для создания интервала, поэтому мы предполагаем, что он сохранит те же переменные, что и раньше, но здесь это не так. Здесь стрелочная функция сохранит prevProps вместе с другими упомянутыми переменными.

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

В этом случае объект области видимости будет совместно использоваться всеми замыканиями, определенными в ComponentDidMount, следовательно, он сохранит все переменные, используемые по крайней мере в одном закрытии. В нашем коде есть закрытие в строке номер 3, которая захватывает prevProps. Несмотря на то, что это закрытие не используется позже и определенно не сохраняется после его использования для вычисления clockPropsHasChanged, оно по-прежнему заставляет все другие замыкания сохранять prevProps.

Теперь захват prevProps в ComponentDidMount может вызвать некоторые из серьезных проблем, когда у нас есть дочерние элементы в нашем компоненте, и мы закончим захватом ссылок на отключенные дочерние элементы через prevProps.children.

Чтобы избежать этой проблемы, мы можем выполнить несколько шагов:

a) Мы можем установить prevProps = null сразу после того, как закончим вычисление clockPropsHasChanged.

б) Мы можем выделить метод, отвечающий за сравнение свойств с уровнем компонента, и передать prevProps этому методу. Как и clockPropsHasChanged = this.compareClockProps (prevProps), он будет создавать наши замыкания в разных областях.

c) Мы также можем извлечь метод, который вызывает обратный вызов setInterval, например this.createCountDown (часы, минуты, секунды).

Это были две основные проблемы, которые вызывают множество утечек памяти в вашем приложении React-Native. Следуя вышеупомянутому разрешению, вы можете избежать проблемы утечки памяти в вашем приложении и можете улучшить его производительность.