表行排序&字符串表现

时间:2009-04-08 13:54:08

标签: javascript jquery performance string

我有一个包含大量行的表,不适合分页。可以通过单击列标题对此表中的行进行排序,该列标题基于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);
        });
    });
});

6 个答案:

答案 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版的jQu​​ery DataTables组件包括从html代码实例化,或者使用AJAX数据源。这对于设置来说非常简单,对于筛选和排序数据来说,它非常快。

我发现一旦我发现大约1600行相当冗长,唯一的方法是加载服务器端数据。

答案 5 :(得分:-4)

Tjena Ola!

这可能与您的问题无关,但我们谈论的行数是多少?对于非常多的行 - 数万 - 表非常慢。更轻量级的解决方案是使用div和css来模拟表。它可能在语义上不正确(ha!表和语义在同一个短语中,谁会想到?),但它的速度要快得多。