Реагировать: решения для общих проблем с утечками памяти

React.js

написать впереди

  • При написании реагирующего кода я часто сталкиваюсь со следующими ошибками
Can't perform a React state update on an unmounted component. This is a no-op......
  • В этой статье сначала рассматривается, что такое утечки памяти, а затем рассматриваются две демонстрации, чтобы увидеть особенности утечек памяти в реакции.

Что такое утечка памяти

  • Программе нужна память для работы. Операционная система или среда выполнения (runtime) должны предоставлять память всякий раз, когда программа запрашивает ее.

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

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

Несколько распространенных утечек памяти в JavaScript

  • Утечка памяти из-за глобальных переменных
function leaks(){  
    leak = '***'; //leak 成为一个全局变量,不会被回收
}
  • Утечки памяти, вызванные замыканиями
var leaks = (function(){  
    var leak = '***';// 被闭包所引用,不会被回收
    return function(){
        console.log(leak);
    }
})()
  • Когда дом очищается или удаляется, утечка памяти, вызванная тем, что событие не очищается
document.querySelector("#demo").addEventListener('click', myFunction);

var para1=document.querySelector("#demo");

para1.parentNode.removeChild(para1);

Если мы уничтожим узел para1, не отменив метод click, это вызовет утечку памяти.

Правильный путь:

document.querySelector("#demo").addEventListener('click', myFunction);

// 我们需要在删除节点前清除挂载的 click 方法
document.querySelector("#demo").removeEventListener("click", myFunction);

var para1=document.querySelector("p1");

para1.parentNode.removeChild(para1);
  • Расширенное чтение, каждый может более внимательно ознакомиться с соответствующими статьями г-на Жуана Ифэна, когда у вас есть время.
  • Вууху. Руань Ифэн.com/blog/2017/0…(Жуан Ифэн)

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

Демонстрация 1:

componentWillMount: function () {
    var onLogin = this.props.onLogin || function () {},
        onLogout = this.props.onLogout || function () {};

    this.on('authChange', function () {
      console.log('user authenticated:', this.state.isAuthenticated);
      return this.state.isAuthenticated
              ? onLogin(this.state)
              : onLogout(this.state);
    }.bind(this));
  },
  • Приведенный выше пример можно увидеть на Stack Overflow, арендодатель находится вcomponentWillMountустановлен, когдаauthChangeсобытие, и реакция сообщила о следующей ошибке:
Не удается выполнить обновление состояния React для размонтированного компонента. Это не работает, но указывает на утечку памяти в вашем приложении. Чтобы исправить это, отмените все подписки и асинхронные задачи в методе componentWillUnmount"
  • Значение: мы не можем установить состояние после уничтожения компонента, чтобы предотвратить утечку памяти

Как это решить?

  • Добавьте следующий код
  componentWillUnmount: function () {
      this.off('authChange', this.authChange);
      this.authChange = null;
  }

Очевидно, эта ситуация является утечкой памяти, вызванной тем, что событие не очищается при разрушении структуры dom, поэтому нам нужноcomponentWillUnmountспособ очистить крепления, когда

Объяснения и решения, связанные с утечкой памяти React

  • Здесь упоминаются утечки памяти, когда мы используем привязку событий, setInterval, setTimeOut или какие-то функции, но они не очищаются перед уничтожением компонента, это вызовет утечку памяти. Здесь мы вручнуюcomponentWillUnmountЧтобы очистить соответствующий метод может быть.

  • Зачем:

    • I would move your function into componentDidMount and add cleanup on componentWillUnmount
    • Important: componentWillMount is called on the server and client, but componentDidMount is only called on the client.
    • Если вы используете eventListeners, setInterval или другие функции, которые нужно очистить, поместите их в componentDidMount, сервер не будет вызывать componentWillUnmount и обычно является причиной утечек памяти.
  • stackoverflow.com/questions/4…

Демонстрация 2:

  • Распространена следующая ситуация:
this.pwdErrorTimer = setTimeout(() => {
    this.setState({
        showPwdError:false
    })
}, 1000);

Таймер установлен для задержки установки состояния, но в течение времени задержки компонент был уничтожен, что вызвало такие проблемы

  • Решение:
  • Используйте функцию ловушки жизненного цикла: componentWillUnmount
componentWillUnmount(){
    clearTimeout(this.pwdErrorTimer);
    clearTimeout(this.userNameErrorTimer);
}

Если вводится react16.8+

В документации упоминаются две важные концепции.

Зачем возвращать функцию в эффект?

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

Когда React очищает эффекты?

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

намекать

Если вы знакомы с функциями жизненного цикла классов React, вы можете рассматривать useEffect Hook как комбинацию трех функций: componentDidMount, componentDidUpdate и componentWillUnmount.

Производное чтение

Вопросы о том, вызовут ли запросы промисов утечку памяти

1. Никогда не разрешенное обещание вызывает утечку памяти?

2. Утечки памяти в циклах с Promise?