关于javascript:jQuery排序导致iOS Safari冻结

jQuery sort causing iOS Safari to freeze

我有一个使用jquery加载XML文件的页面,然后将其内容输出到该页面。

最近,我在输出中添加了一个排序功能,这导致iPod touch上的Safari挂起1分钟或2分钟(取决于我排序的字段数),iPad上的挂起时间不足1分钟。在火狐4.0.1上,同样的排序会在几秒钟内返回。

恐怕这只是iOS的一个限制,但在我删除排序之前,也许可以进行优化。

在过滤器之前,XML中有357项。过滤后,有199个项目被排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var videoGames = $($.parseXML(videoGameXml)).find("game");
videoGames = videoGames.filter(function (a) {
    return ($(this).attr('addOn') !="true" && $(this).find('own').text() =="yes");
});
videoGames.sort(function (a, b) {
    var firstTitle = $(a).find('title').text().toLowerCase();
    var secondTitle = $(b).find('title').text().toLowerCase();
    var firstSystem = ($(a).find("console").text() +"" + $(a).find("version").text()).toLowerCase();
    var secondSystem = ($(b).find("console").text() +"" + $(b).find("version").text()).toLowerCase();

    if (firstSystem != secondSystem) {
        if (firstSystem > secondSystem) {
            return 1;
        } else {
            return -1;
        }
    } else {
        if (firstTitle > secondTitle) {
            return 1;
        } else if (secondTitle < firstTitle) {
            return -1;
        }
    }
    return 0;
});
videoGames.each(function () {
    // runs quickly, so removed
});

请注意,如果我删除系统检查作为一个初始的"优化",它会将iPod touch上的时间缩短一半,但仍然会导致上述1分钟以上的挂起。

所以,这是一个iOS设备限制,还是我可以优化我的排序?


每次您执行$(a)时,它都会执行一组非常复杂的操作,因此您最好缓存它。另外,如果系统不同,也不需要标题。这个版本应该会加快一点速度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
videoGames.sort(function (a, b) {
    var first = $(a);
    var second = $(b);
    var firstSystem = (first.find("console").text() +"" + first.find("version").text()).toLowerCase();
    var secondSystem = (second.find("console").text() +"" + second.find("version").text()).toLowerCase();

    if (firstSystem != secondSystem) {
        if (firstSystem > secondSystem) {
            return 1;
        } else {
            return -1;
        }
    } else {
        var firstTitle = first.find('title').text().toLowerCase();
        var secondTitle = second.find('title').text().toLowerCase();

        if (firstTitle > secondTitle) {
            return 1;
        } else if (secondTitle < firstTitle) {
            return -1;
        }
    }
    return 0;
});

还可以缓存对象中的值

然后,而不是:

1
var firstSystem = (first.find("console").text() +"" + first.find("version").text()).toLowerCase();

做:

1
2
3
4
5
var firstSystem = first.data('system');
if (!firstSystem) {
    firstSystem = (first.find("console").text() +"" + first.find("version").text()).toLowerCase();
    first.data('system') = firstSystem;
}


您应该像这样移动任何选择器调用:

1
var firstTitle = $(a).find('title').text().toLowerCase();

从比较器函数中去掉。比较器函数应该是轻量级的。

要么使用children()next()等,要么扫描您设置的一次,并在前面创建一个键数组,然后使用这些键对其进行排序。

比较器函数将被称为2n * ln(n)次(取决于所使用的算法),其中n是集合中的多个元素。所以你的代码至少要做两次同样昂贵的计算。