Redux + ImmutableJS - как мусор собирать слишком большой магазин?

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

Как я могу "удалить" что-нибудь из магазина, чтобы данные не замедляли приложение? Я знаю, что это будет против его основного принципа, но как еще вы его решаете?

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

И я не хочу заставлять пользователя перезагружать страницу, конечно.

Ответ 1

Я бы предложил вместо хранения всех данных в магазине сохранить указатель на решение памяти (localstorage, REDIS и т.д.). Я бы использовал PouncDB и сохранил номер версии _rev только в моем магазине.

Ответ 2

Triple-Check Это действительно раздутие памяти, а не просто ненужное повторное рендеринг/повторное вычисление

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

Вы можете решить эту проблему путем судебного использования библиотеки reselect или с помощью другого типа memoization, который будет извлекать данные из ваши редукторы таким образом, чтобы избежать ненужной перерасчеты. Аналогично, убедитесь, что вы не излишне перерисовываете каждый элемент во всем списке только при смене одной строки.

Избавиться от ссылок на предыдущее состояние

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

Если вам действительно нужно идти по этому пути, важно, чтобы вы не сохранили старые данные страницы "живыми", если хотите, потому что JavaScript только мусор собирает вещи, на которые больше не ссылаются.

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

Итак, я бы удостоверился, что я не использую что-то вроде средств для разработчиков redux, которые сохраняют предыдущее состояние.

Затем в редукторе создайте новый объект, который каким-либо образом не использует предыдущие данные, а скорее вернет новый объект с новыми данными:

const data = (state, action) => {
  switch (action.type) {
    case 'RETRIEVE_DATA_SUCCESS':
      return action.payload;
    default:
      return state
  }
}

Я предлагаю прочитать здесь инструменты профилирования памяти Chrome здесь, чтобы убедиться, что это работает правильно.

Ответ 3

Предыдущее сообщение неверно о том, что Immutablejs сохраняет старые данные "живыми"... ну, в том смысле, что это описано. Immutablejs использует структурный обмен, а это означает, что он создаст только новый node и его детей, в то же время разделив остальную часть trie со старыми данными. Если вы посмотрите на изображение ниже, вы увидите, что зеленые и желтые точки справа - это новые данные, разделяющие его структуру со старыми данными.

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

Если бы вы глубоко клонировали каждый объект на один идиоматический Redux, тогда у вас была бы еще более серьезная проблема с памятью без структурного обмена immutablejs. Поэтому, не видя какого-то кода, я сомневаюсь, что это неясно.

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

const immVal = List([1,2,3]) console.log([...immVal.values()])

Ли Байрон (создатель immutablejs) structual sharing @23: 40 и сбор мусора @24: 50

изображение структурного обмена

Ответ 4

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