утечка памяти при создании DOM
вот уже пару дней бьюсь над кодом...суть такова:
есть таблица сформированная с помощью jquery.Datatables...для получения данных используется serverside(php возвращает json)...после отрисовки самой таблицы необходмо наложить на нее дополнительные DOM элементы(ссылки и прочее), для чего написана небольшая функция fnRend с использованием jquery, кот вызывается один раз после отрисовки всей таблицы...вот в ней то и проблема... если обновлять таблицу без вызова fnRend - все работает быстро и практически без утечек памяти... если использовать fnRend, то при каждом обновлении таблицы происходит небольшая, но существенная утечка - особенно это заметно в IE(6 и 8): за 15 мин с обновлением через каждые 10сек(таблица 10х100 ячеек) память вырастает метров на 70!... уже перечитал несколько статей - оптимизировал насколько мог функцию, но все равно что-то остается в памяти при обновлении(обновляется на страница, а только таблица)... может кто посмотрит проф взглядом и найдет еще недочеты в функции, кот могу приводить к утечке?...
function fnRend()
{
//цикл по каждому row таблицы
$(oTable_q.fnGetNodes()).each( function() {
//массив изначальных данных в ячейках
var aData = [];
for (var i = 0, len = $("td", this).length; i < len; i++) {
aData.push($("td:eq(" + i + ")", this).html());
}
//преобразую данные 1-й ячейки - втсавка 3-х ссылок
var td = $("<div></div>");
var td0 = td.clone();
$('td:eq(0)', this).html(td0);
td0.append('<a href="#"></a>')
.append(' ')
.append('<a href="#"></a>')
.append(' ')
.append('<a href="#"></a>')
.find('a:eq(0)')
.append(aData[0])
.attr("id", "result")
.attr("title", "Результат команды")
.end()
.find('a:eq(1)')
.attr("title", "Результат команды в RAW-формате")
.append('<img id="raw" src="./images/pic_agr.gif" border=0>')
.end()
.find('a:eq(2)')
.attr('id', 'repeat')
.attr("title", "Повтор команды")
.addClass('iframe')
.append('<img id="repeat" src="./images/pic_agr.gif" border=0>');
//преобразую данные 7-й ячейки
var aData7 = aData[7].match(/^([A-Z]+):::([01])$/);
$('td:eq(7)', this).html(aData7[1]);
if (aData7[2] == '1') {
$('td', this).addClass('qrowdisable');
}
//преобразую данные 6-й ячейки - преобразование времени из
//unixtime в читабельный вид
var times = aData[6].split(':');
var dec = ['00','01','02','03','04','05','06','07','08','09'];
var day, month, year, date, hour, min, sec, time;
for (i = 0; i < 3; i++)
{
times[i] = new Date(times[i] * 1000);
day = ((day = times[i].getDate()) < 10) ? dec[day] : day;
month = ((month = times[i].getMonth() + 1) < 10) ? dec[month] : month;
year = times[i].getUTCFullYear().toString().substring(2);
date = [day, month, year];
hour = ((hour = times[i].getHours()) < 10) ? dec[hour] : hour;
min = ((min = times[i].getMinutes()) < 10) ? dec[min] : min;
sec = ((sec = times[i].getSeconds()) < 10) ? dec[sec] : sec;
time = [hour, min, sec];
delete times[i];
times[i] = date.join('.') + " " + time.join(':');
}
var td6 = td.clone();
$('td:eq(6)', this).html(td6);
td6.append('<img src="./images/pic_agr.gif">')
.append('<img src="./images/pic_agr.gif">')
.append(' ')
.append('<img src="./images/pic_agr.gif">')
.find('img:eq(0)')
.attr('id', 'qtime')
.attr("title", times[0])
.after(' ' + times[0] + ' ')
.end()
.find('img:eq(1)')
.attr('id', 'stime')
.attr("title", times[1])
.end()
.find('img:eq(2)')
.attr('id', 'etime')
.attr("title", times[2]);
times = null;
//помечаю нужные ячейки тегом span
$('td', this).each( function(i) {
if ((i >= 1 && i <=5) || i == 7 || i == 8)
{
var k = (i == 7 || i == 8) ? i - 1 : i;
$(this).wrapInner('<span id="td' + k + '"></span>')
.find('span')
.css("cursor", "pointer");
}
});
aData = null;
td = null;
});
//onClick на всю таблицу - и выборка действия в зависимости от места евента
$('#queue_table').unbind();
$('#queue_table').click(function(e) {
var form_params = (window.navigator.userAgent.match(/MSIE/)) ? 'left=200,top=100,height=640,width=900,scrollbars=yes' : '';
var data;
if (e.target.nodeName == 'SPAN')
{
var col = {
0 : 'search_tt',
1 : 'search_rr',
2 : 'search_yy',
3 : 'search_ww',
4 : 'search_oo',
5 : 'search_pp',
6 : 'search_zz',
7 : 'search_ss'
};
var oSettings = oTable_q.fnSettings();
var k = $(e.target).attr('id').replace("td", "");
$("input[id=" + col[k]+ "]").val($(e.target).text());
oSettings.aoPreSearchCols[k].sSearch = $(e.target).text();
//обновление самой таблицы
oTable_q.fnDraw(false);
oSettings = null;
col = null;
}
//открытие нового окна
else if ($(e.target).attr('id') == 'result')
{
data = $(e.target).text();
window.open('/cgi-bin/result.pl?guid=' + data, '', form_params);
data = null;
}
else if ($(e.target).attr('id') == 'raw')
{
data = e.target.parentNode.parentNode;
data = $("a:eq(0)", data).text();
window.open('/cgi-bin/show.pl?guid=' + data, '', form_params);
data = null;
}
});
}
|
Я вот, кстати, у знатоков jQuery спросить хотел.
Он где-то у себя хранит элементы, которые уже давно потерты? Просто брал элемент через jQuery, что-то с ним делал, потом этот элемент терся через innerHTML родителя. Обычный document.getElementById('id') - выдавал undefind, а $('#id') показывал и сам элемент и все его атрибуты, присвоенные ранее. |
посмотрел с помощью JavaScript Memory Validator...самыми трубоемкими оказались цилы each...изменил их так:
первый(где формируется массив aData) вообще убрал - ведь пользовался только 3-ми значениями из него...стал брать значения сразу через $("td:eq(_номер_ячейки_)", this).html()... второй заменил на такую конструкцию:
var tds = [1, 2, 3, 4, 5, 7, 8];
var tde = $("<span></span>").css("cursor", "pointer");
for (i = 0; i < tds.length; i++)
{
var k = (tds[i] == 7 || tds[i] == 8) ? tds[i] - 1 : tds[i];
data = $("td:eq(" + tds[i] + ")", this).html();
var tdec = tde.clone();
$("td:eq(" + tds[i] + ")", this).html(tdec.html(data));
tdec.attr('id', 'td' + k);
}
утечки значительно уменьшились, но все равно есть - за час набежало 250 метров... |
| Часовой пояс GMT +3, время: 18:32. |