Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Как правильно удалить старое содержимое innerHTML перед новым присвоением? (https://javascript.ru/forum/misc/81447-kak-pravilno-udalit-staroe-soderzhimoe-innerhtml-pered-novym-prisvoeniem.html)

Was-Ja 28.11.2020 03:46

Как правильно удалить старое содержимое innerHTML перед новым присвоением?
 
Добрый день,

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

Погуглил, нашел и адаптировал под себя такой вариант

function ReSet_innerHTML(id, html)
{ const myNode = ID(id);
  while (myNode.firstChild) {
    myNode.removeChild(myNode.lastChild);
  }
  myNode.innerHTML=html;
}


потерь по памяти стало существенно меньше, но, память все равно теряется.

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

Если это так, пожалуйста, посоветуйте, как проще сделать правильно удаление, чтоб удалить реально все?

Спасибо!

voraa 28.11.2020 08:25

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

var block = document.getElementById('block')

Потом

block.remove();

или в его родительском

parent.innerHTML = "новое содержимое";

Но пока переменная block будет ссылаться на этот элемент он будет занимать место в памяти вместе со всеми своими потомками, обработчиками событий и картинками.

Was-Ja 30.11.2020 10:29

Спасибо, voraa, за ответ!

Цитата:

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

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

Грешить не на кого, я пока сторонних фреймворков не пользую.

Если занулять старое содержимое, переписывая innerHTML, то за каждый шаг теряется 2-3мбайта, если делать с удалением child как я написал выше, остается 300кбайт, но все равно остается... Из-за этого я предполагаю, что все-таки дело в способе удаления.

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

voraa 30.11.2020 13:53

Ну да, способ удаления может влиять. Но все равно в памяти будут оставаться элементы, на которые есть ссылки
Вот, например, есть
<div id='cotainer'>
</div>

И вы делаете
document.getElementById('container').innerHTML = "<div id='block'><div id='ch1'>...</div><div id='ch2'>...</div></div>"

let ch1 = document.getElementById('ch1')

Потом снова
document.getElementById('container').innerHTML = "<div id='block'><div id='ch1'>...</div><div id='ch2'>...</div></div>"


Но все старое содержимое не удалится. Потому, что ch1 ссылается на свой элемент, он, через свойство parentElement ссылается на div#block, а тот ссылается на всех своих потомков. И все сидит в памяти

Если сначала удалить через remove, то в памяти останутся только div#ch1 и его потомки. И будут сидеть там, пока переменная ch1 ссылается на него.

Was-Ja 30.11.2020 16:27

Спасибо большое, voraa, что помогаете!

Цитата:

Сообщение от voraa (Сообщение 531258)
И вы делаете
document.getElementById('container').innerHTML = "<div id='block'><div id='ch1'>...</div><div id='ch2'>...</div></div>"

let ch1 = document.getElementById('ch1')

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

Data=JSON.parse(xhr.response);

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

Data=JSON.parse(xhr.response);

но пока не помогло.

voraa 30.11.2020 17:11

И в этом объекте лежит и то, что приходит с сервера, и то, что вы получаете сами?
Ведь с сервера приходит только то, что нужно как то поместить в элементы, а сами ссылки на элементы, которые получаются по
getElementById или querySelector с сервера не приходят.
Или вы с этими элементами никак не работаете, обработчики им не назначаете, классы и стили не меняете?

Тогда есть вариант, что вы видите утечку памяти в те моменты, когда ее очистка не произошла. Это не сразу происходит. Сборщик мусора работает в какие то определенные моменты времени. И не всегда очищает все, что требует очистки за один раз.

Was-Ja 30.11.2020 21:00

Спасибо большое, voraa, за содействие!

Цитата:

Сообщение от voraa (Сообщение 531260)
И в этом объекте лежит и то, что приходит с сервера, и то, что вы получаете сами?

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

Цитата:

Сообщение от voraa (Сообщение 531260)
Тогда есть вариант, что вы видите утечку памяти в те моменты, когда ее очистка не произошла. Это не сразу происходит. Сборщик мусора работает в какие то определенные моменты времени. И не всегда очищает все, что требует очистки за один раз.

какой-то кривой, похоже, в файерфоксе сборщик мусора.

У меня примерно раз в 10 секунд приходит новый комплект данных (не всегда так часто, но есть режимы, когда такое происходит).

Пришедших данных с сервера не много, около сотни килобайт. Из них я рисую с десяток канвасов и биндю на канвасы евенты, связанные с отрисовкой. В канвасах нарисованы 3Д модели молекул, мышкой их можно повертеть и включить/выключить отрисовку, например, водородов.

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

Названия div всегда имеют какой-то смысл, типа "MolFrame_"+Index, где Index - это номер молекулы. По таким названиям я и генерю ссылки, когда срабатывает евент и мне надо что-то в канвасе перерисовать.

Еще одновременно с этим перерисовывается панель с кнопками (картинки загружаются из локальных копий, которые сохранены в виде текста "data:image/png;base64,iVBOR..."

По приходе нового комплекта данных с сервера вся эта ботва полностью перерисовывается.

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


Часовой пояс GMT +3, время: 09:35.