在javascript性能中动态创建大型html表
我有一个用于数据分析的应用程序,我在创建表时遇到了一些性能问题。 数据是从文档中提取的,重要的是所有数据都显示在一个页面上(不幸的是,分页不是一个选项)。
使用jQuery,我向服务器发出ajax请求以检索数据。 完成请求后,我将数据传递给输出函数。 输出函数使用for循环遍历数据数组并将行连接到变量。 循环完成后,包含该表的变量将附加到页面上的现有div,然后我继续将事件绑定到表以处理数据。
使用一小组数据(~1000-2000行),它的工作效果相对较好,但有些数据集包含超过10,000行,导致Firefox崩溃,关闭或无响应。
我的问题是,有没有更好的方法来完成我正在做的事情?
这是一些代码:
//This function gets called by the interface with an id to retrieve a document function loadDocument(id){ $.ajax({ method: "get", url: "ajax.php", data: {action:'loadDocument',id: id}, dataType: 'json', cache: true, beforeSend: function(){ if($("#loading").dialog('isOpen') != true){ //Display the loading dialog $("#loading").dialog({ modal: true }); }//end if },//end beforesend success: function(result){ if(result.Error == undefined){ outputDocument(result, id); }else{ }//end if if($('#loading').dialog('isOpen') == true){ //Close the loading dialog $("#loading").dialog('close'); }//end if }//end success });//end ajax };//end loadDocument(); //Output document to screen function outputDocument(data, doc_id){ //Begin document output var rows = ''; rows += ''; rows += ''; rows += 'ID '; rows += 'Status '; rows += 'Name '; rows += 'Actions '; rows += 'Origin '; rows += ' '; rows += ''; rows += ''; for(var i in data){ var recordId = data[i].id; rows += ''; rows += '' + recordId + ' '; rows += '' + data[i].status + ' '; rows += '' + data[i].name + ' '; rows += ''; rows += ''; rows += ''; rows += ' '; rows += '' + data[i].origin + ' '; rows += ' '; }//end for rows += ''; rows += '
'; $('#documentRows').html(rows);
我最初使用jQuery每个循环,但切换到for循环,削减了一些ms。
我想过使用谷歌齿轮这样的东西来尝试卸载一些处理(如果在这种情况下可能的话)。
有什么想法吗?
joinHi,
渲染是一个问题,但是在循环中连接这么多字符串也存在问题,特别是一旦字符串变得非常大。 最好将字符串放入数组的各个元素中,然后最终使用“join”一次创建巨大的字符串。 例如
var r = new Array(); var j = -1, recordId; r[++j] = 'ID Status Name Actions Origin '; for (var i in data){ var d = data[i]; recordId = d.id; r[++j] = ''; r[++j] = recordId; r[++j] = ' '; r[++j] = d.status; r[++j] = ' '; r[++j] = d.name; r[++j] = ' '; r[++j] = d.origin; r[++j] = ' '; } r[++j] = '
'; $('#documentRows').html(r.join(''));
此外,我将使用此处显示的数组索引方法,而不是使用“推送”,因为除了谷歌浏览器之外,所有浏览器都更快,根据这篇文章 。
显示那么多行导致浏览器的渲染引擎变慢,而不是JavaScript引擎。 不幸的是,你不能做很多事情。
最好的解决方案是不要通过分页或虚拟滚动同时显示这么多行。
构建字符串的方式将导致大量垃圾回收。
随着字符串变得越来越长,javascript引擎必须继续分配更大的缓冲区并丢弃旧的缓冲区。 最终,如果不回收所有旧字符串的剩余部分,它将无法分配足够的内存。
随着字符串变长,这个问题变得更糟。
而是尝试使用jQuery操作API一次向DOM添加新元素
还要考虑仅渲染可见内容并实现自己的滚动。
你可以做几件事来提高性能:
- 你的rows变量越来越大,所以不要将html存储在一个变量中。 解决方案可以是
$.each()
函数以及将元素附加到DOM中的每个函数。 但这是一个小调整。 - Html生成很好,但您可以尝试DOM创建和追加。 像
$('
。
')
- 最后,这肯定会解决您的问题:在第一个ajax调用中使用多个ajax调用收集可用的数据量并获取大约1,000个或者可能是更多数据。 并使用其他调用来收集剩余数据。 如果需要,可以明智地使用同步调用或异步调用。
但尽量避免存储价值。 你的DOM大小将是巨大的,但它应该适用于现代浏览器而忘记IE6。
@ fuel37:例子
function outputDocumentNew(data, doc_id) { //Variable DOM's var rowSample = $(' ').addClass('row-class'); var colSample = $(' ').addClass('col-class'); var spanSample = $('').addClass('span-class'); var inputButtonSample = $('').addClass('input-class'); //DOM Container var container = $('#documentRows'); container.empty().append('
'); //Static part var head = '\ \ ID \ Status \ Name \ Actions \ Origin \ \ '; container.append(head); var body = $(''); container.append(body); //Dynamic part $.each(data, function (index, value) { var _this = this; //DOM Manupulation var row = rowSample.clone(); //Actions var inpFailOne = inputButtonSample.clone().val('F').attr('rev', _this.id).addClass('failOne').click(function (e) { //do something when click the button. }); var inpPromoteOne = inputButtonSample.clone().val('P').attr('rev', _this.id).addClass('promoteOne').click(function (e) { //do something when click the button. }); row .append(colSample.clone().append(_this.id)) .append(colSample.clone().append(spanSample.colne().addClass('status').append(_this.status))) .append(colSample.clone().append(spanSample.colne().addClass('name').append(_this.name))) .append(colSample.clone().append(inpFailOne).append(inpPromoteOne)) .append(colSample.clone().append(_this.origin)); body.append(row); }); }
在这个过程中,您需要创建和维护用于操作的id或类。 您可以控制绑定事件并操纵那里的每个元素。
回答格式化
如果你这样做会发生什么
for(var i in data){ var record = data[i]; var recordId = record.id; rows += ''; rows += '' + recordId + ' '; rows += '' + data[i].status + ' '; rows += '' + record.name + ' '; rows += ''; rows += ''; rows += ''; rows += ' '; rows += '' + record.origin + ' '; rows += ' '; }//end for
对于其他人的建议(我还没有足够的声誉来评论,抱歉!),您可以尝试使用TableSorter插件来处理一次只显示可用数量的数据。
我不知道它在很多行中的表现如何,但它们的示例数据大约是1000行。
这对JS性能没有帮助,但会减轻浏览器渲染器的负担。
可以尝试这个……
改善循环
改进String Concat
var tmpLst = []; for (var i=0, il=data.length; i'); tmpLst.push(''); ...ect... } rows += tmpLst.join('');
这可能会挤压额外的性能……
var lstReset = i * lstReset.length; tmpLst[lstReset + 1]='