28.11.2020, 03:46
|
Кандидат Javascript-наук
|
|
Регистрация: 20.09.2020
Сообщений: 130
|
|
Как правильно удалить старое содержимое innerHTML перед новым присвоением?
Добрый день,
опрометчиво заложил в своей логике использование innerHTML, часто в нее пишу гремучую строку, которая содержит множество вложенных divов, а внутри них - все подряд, и канвасы, и картинки, и таблицы и евенты биндю. Заметил, что память от предыдущего содержимого не освобождается...
Погуглил, нашел и адаптировал под себя такой вариант
function ReSet_innerHTML(id, html)
{ const myNode = ID(id);
while (myNode.firstChild) {
myNode.removeChild(myNode.lastChild);
}
myNode.innerHTML=html;
}
потерь по памяти стало существенно меньше, но, память все равно теряется.
Скажите, пожалуйста, правильно ли я понимаю, что мой способ не удаляет евенты, которые там были забиндены и картинки, которые там были вставлены?
Если это так, пожалуйста, посоветуйте, как проще сделать правильно удаление, чтоб удалить реально все?
Спасибо!
|
|
28.11.2020, 08:25
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,754
|
|
Как удалять совершенно без разницы.
Если остаются какие либо ссылки на старые элементы, то эти элементы, а так же их дочерние все равно не будут удалены из памяти.
Например, где то вы сделали
var block = document.getElementById('block')
Потом
block.remove();
или в его родительском
parent.innerHTML = "новое содержимое";
Но пока переменная block будет ссылаться на этот элемент он будет занимать место в памяти вместе со всеми своими потомками, обработчиками событий и картинками.
Последний раз редактировалось voraa, 28.11.2020 в 08:36.
|
|
30.11.2020, 10:29
|
Кандидат Javascript-наук
|
|
Регистрация: 20.09.2020
Сообщений: 130
|
|
Спасибо, voraa, за ответ!
Сообщение от voraa
|
Как удалять совершенно без разницы.
Если остаются какие либо ссылки на старые элементы, то эти элементы, а так же их дочерние все равно не будут удалены из памяти...
|
да, верно, Вы это мне говорили и я приложил все усилия чтобы этого не было. То есть у меня все данные лежат в одном объекте, и я регулярно этот объект удаляю и записываю в него новые данные.
Грешить не на кого, я пока сторонних фреймворков не пользую.
Если занулять старое содержимое, переписывая innerHTML, то за каждый шаг теряется 2-3мбайта, если делать с удалением child как я написал выше, остается 300кбайт, но все равно остается... Из-за этого я предполагаю, что все-таки дело в способе удаления.
Код не получается выложить, я что-то с сервером накосячил (по локалке все работает, а через мой сервер - нет), если быстро пофиксю, положу и покажу когда и где это происходит.
|
|
30.11.2020, 13:53
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,754
|
|
Ну да, способ удаления может влиять. Но все равно в памяти будут оставаться элементы, на которые есть ссылки
Вот, например, есть
<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 ссылается на него.
|
|
30.11.2020, 16:27
|
Кандидат Javascript-наук
|
|
Регистрация: 20.09.2020
Сообщений: 130
|
|
Спасибо большое, voraa, что помогаете!
Сообщение от voraa
|
И вы делаете
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);
но пока не помогло.
|
|
30.11.2020, 17:11
|
|
Профессор
|
|
Регистрация: 03.02.2020
Сообщений: 2,754
|
|
И в этом объекте лежит и то, что приходит с сервера, и то, что вы получаете сами?
Ведь с сервера приходит только то, что нужно как то поместить в элементы, а сами ссылки на элементы, которые получаются по
getElementById или querySelector с сервера не приходят.
Или вы с этими элементами никак не работаете, обработчики им не назначаете, классы и стили не меняете?
Тогда есть вариант, что вы видите утечку памяти в те моменты, когда ее очистка не произошла. Это не сразу происходит. Сборщик мусора работает в какие то определенные моменты времени. И не всегда очищает все, что требует очистки за один раз.
|
|
30.11.2020, 21:00
|
Кандидат Javascript-наук
|
|
Регистрация: 20.09.2020
Сообщений: 130
|
|
Спасибо большое, voraa, за содействие!
Сообщение от voraa
|
И в этом объекте лежит и то, что приходит с сервера, и то, что вы получаете сами?
|
да, именно так. Я пошел на такое извращение, чтобы проще удалять ссылки и гарантировать (по крайней мере себе) что все с предыдущего шага удалено.
Сообщение от voraa
|
Тогда есть вариант, что вы видите утечку памяти в те моменты, когда ее очистка не произошла. Это не сразу происходит. Сборщик мусора работает в какие то определенные моменты времени. И не всегда очищает все, что требует очистки за один раз.
|
какой-то кривой, похоже, в файерфоксе сборщик мусора.
У меня примерно раз в 10 секунд приходит новый комплект данных (не всегда так часто, но есть режимы, когда такое происходит).
Пришедших данных с сервера не много, около сотни килобайт. Из них я рисую с десяток канвасов и биндю на канвасы евенты, связанные с отрисовкой. В канвасах нарисованы 3Д модели молекул, мышкой их можно повертеть и включить/выключить отрисовку, например, водородов.
Гружу все всегда в один и тот же объект. В нем завожу всегда несколько дополнительных объектов, в основном матрицы поворотов-трансформаций и какие-то включатели-выключатели. Ни одного названия div явно в этой структуре не храню.
Названия div всегда имеют какой-то смысл, типа "MolFrame_"+Index, где Index - это номер молекулы. По таким названиям я и генерю ссылки, когда срабатывает евент и мне надо что-то в канвасе перерисовать.
Еще одновременно с этим перерисовывается панель с кнопками (картинки загружаются из локальных копий, которые сохранены в виде текста "data:image/png;base64,iVBOR..."
По приходе нового комплекта данных с сервера вся эта ботва полностью перерисовывается.
Так вот я прождал больше часа, тыкаясь после каждой такой перерисовки в снапшот, занятость памяти всегда росла, и даже число используемых картинок все время только росло, хотя у меня только 10 таких встроенных картинок всего. То есть я ни разу не заметил, как сборщик мусора сработал и это меня понятно очень напрягло.
|
|
|
|