开发者

jQuery sort causing iOS Safari to freeze

I have a page that is using jQuery to load an XML file, which I'm then outputting the contents of to the page.

Recently I added a sorting function to the output which is causing a 1+ or 2+ minute hang on Safari on an iPod Touch (depending upon how many fields I sort by) and a less than 1 minute hang on an iPad. The same sort returns within a few seconds on Firefox 4.0.1.

I'm afraid it's just a limitation of the iOS, but before I removed the sort, perhaps there's an optimization that could be made.

Before the filter there's 357 items in the XML. After the filter there's 199 items that are sorted开发者_运维技巧 through.

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
});

Note that if I remove the system check as an initial 'optimization' that cuts the time about in half on the iPod Touch, but still results in the 1+ minute hang mentioned above.

So, is it an iOS device limitation, or can I optimize my sort?


Every time you do $(a) it will perform a very complex set of operations, so you better cache it. Also, you don't need the Title if System is different. This version should speed it up a bit:

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;
});

You could also cache the values in the object

Then, instead of:

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

Do:

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


You should move any selectors calls like this:

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

out from the comparator function. The comparator function is supposed to be lightweight.

Either use children(), next() and the like or scan you set once and create an array of keys upfront and then sort it using those keys.

The comparator function will be called 2n * ln(n) times (depends on algorithm used) where n is a number of elements in a set. So your code does the same expensive calculations twice at least.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜