我有一个包含大量行的表,不适合分页。可以通过单击列标题对此表中的行进行排序,该列标题基于http://www.exforsys.com/tutorials/jquery/jquery-basic-alphabetical-sorting.html触发客户端排序算法。该函数动态地向每行添加“expando”属性,从而缓存密钥预排序:
row.sortKey = $(row).children('td').eq(column).text().toUpperCase();
正如您所看到的,属性值只是设置为单击列的内容,并在排序完成后被丢弃(为空)。性能实际上非常好 - 但包含更多文本的列似乎更慢排序。
由于排序只是为了让用户更容易找到他们正在寻找的行,我想通过使用substr(0,7)或其他东西裁剪键值可以加快速度(八个字符应提供足够的精度)。但是,我发现执行substr()会导致比保存更多的性能成本,如果有的话,它会使排序变慢。
有没有人知道可以应用于此方法的任何(其他)优化?
这是一个更完整的例子:
var rows = $table.find('tbody > tr').get();
$.each(rows, function(index, row) {
row.sortKey = $(row).children('td').eq(column).text().toUpperCase()
})
rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) return -1
if (a.sortKey > b.sortKey) return 1
return 0
})
$.each(rows, function(index, row) {
$table.children('tbody').append(row)
row.sortKey = null
})
编辑:这是我的代码的最终版本,其中包含以下答案中提供的许多优化:
$('table.sortable').each(function() {
var $table = $(this);
var storage = new Array();
var rows = $table.find('tbody > tr').get();
$('th', $table).each(function(column) {
$(this).click(function() {
var colIndex = this.cellIndex;
for(i=0;i<rows.length;i++) {
rows[i].sortKey = $(rows[i].childNodes[colIndex]).text().toUpperCase();
}
rows.sort(function(a, b) {
if (a.sortKey < b.sortKey) return -1;
if (a.sortKey > b.sortKey) return 1;
return 0;
});
for(i=0;i<rows.length;i++) {
storage.push(rows[i]);
rows[i].sortKey = null;
}
$table.children('tbody').append(storage);
});
});
});
答案 0 :(得分:5)
您提供的示例有几个问题。第一个问题是您在循环内使用jquery选择列。这是一个主要的性能损失。如果您对html代码有任何控制权,我建议您使用普通的DOM方法来获得想要排序的所需列。请注意,有时当您可能需要表格单元节点时,您可能会获得一个文本节点。我稍后再回过头来。 for循环更快,所以你可以考虑使用它而不是$ .each,但我建议你对它进行基准测试。
我拿了你的例子并创建了一个包含1000行的表。在我的机器上花了大约750毫秒来对它进行排序。我做了一些优化(见下面的代码)并设法将其降低到200毫秒。排序本身大约需要20毫秒(不错)。
var sb = [];
sb.push("<table border='1'>");
var x;
for (var i = 0; i < 1000; i++) {
x = Math.floor(Math.random() * 1000);
sb.push("<tr><td>data");
sb.push(x);
sb.push("</td></tr>");
}
sb.push("</table>");
document.write(sb.join(""));
$table = $("table");
var rows = $table.find('tbody > tr').get();
var columnIndex = 0;
var t = new Date();
$.each(rows, function(index, row) {
row.sortKey = $(row.childNodes[columnIndex]).text();
});
alert("Sort key: " + (new Date() - t) + "ms");
t = new Date();
rows.sort(function(a, b) {
return a.sortKey.localeCompare(b.sortKey);
});
alert("Sort: " + (new Date() - t) + "ms");
t = new Date();
var tbody = $table.children('tbody').get(0);
$.each(rows, function(index, row) {
tbody.appendChild(row);
delete row.sortKey;
})
alert("Table: " + (new Date() - t) + "ms");
当您为速度编写时,您希望每次迭代尽可能快,因此不要在循环中执行您可以在其外部执行的操作。例如,移动$ table.children('tbody')。get(0);在最后一个循环之外加速了事情。
至于使用DOM方法访问列,您需要的是列索引,因此您可以遍历第12列,直到找到正确的列(前提是html格式对于th标签和td标签是相同的)。然后,您可以使用该索引来获取正确的行子节点。
此外,如果表是静态的并且用户可能会对其进行更多排序,则应该缓存行而不删除sortKey属性。然后节省约30%的排序时间。还有表内容的问题。如果内容是文本,则此排序方法很好。如果它包含数字等,那么你需要考虑一下,因为我使用的是localeCompare,它是String类的一种方法。
答案 1 :(得分:2)
我能想到的一个优化是修改此代码:
$.each(rows, function(index, row) {
$table.children('tbody').append(row)
row.sortKey = null
})
而不是一次附加一行,添加更大的块,或者如果可能的话附加所有块。为此,您需要先创建一个包含所有行的字符串,然后立即将其全部附加。
使用array.push和array.join连接字符串
答案 2 :(得分:1)
另一项绩效改善: 不要使用$ .each,而是使用常规for循环而不是你可以帮助它。常规循环稍快。
这篇博文也可能有用,如果不是现在,那么将来:
http://notetodogself.blogspot.com/2009/02/building-fast-jquery-plugins.html
答案 3 :(得分:0)
根据mkoryak的建议,我现在修改了代码以在数组中组装行,然后将它们全部附加到一起:
$.each(rows, function(index, row) {
storage.push(row);
row.sortKey = null;
});
$table.children('tbody').append(storage);
这似乎提高了约25%的性能 - 排序1500行现在需要~3s而不是之前的~4s。
答案 4 :(得分:0)
我使用DataTables jQuery plugin进行此类工作,之前我曾使用YUI DataTable组件。 1.5 beta版的jQuery DataTables组件包括从html代码实例化,或者使用AJAX数据源。这对于设置来说非常简单,对于筛选和排序数据来说,它非常快。
我发现一旦我发现大约1600行相当冗长,唯一的方法是加载服务器端数据。
答案 5 :(得分:-4)
Tjena Ola!
这可能与您的问题无关,但我们谈论的行数是多少?对于非常多的行 - 数万 - 表非常慢。更轻量级的解决方案是使用div和css来模拟表。它可能在语义上不正确(ha!表和语义在同一个短语中,谁会想到?),但它的速度要快得多。