Сортировка jQuery, вызывающая замораживание iOS Safari

У меня есть страница, использующая jQuery для загрузки XML файла, который затем выводит содержимое страницы.

Недавно я добавил функцию сортировки для вывода, которая вызывает 1+ или 2+ минуты в Safari на iPod Touch (в зависимости от того, сколько полей я сортирую) и менее 1 минуты висит на iPad. Тот же вид возвращается в течение нескольких секунд в Firefox 4.0.1.

Я боюсь, что это просто ограничение iOS, но до того, как я удалил сортировку, возможно, была сделана оптимизация.

Перед фильтром есть 357 элементов в XML. После фильтра есть 199 элементов, отсортированных через.

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-устройство или я могу оптимизировать свой вид?

Ответ 1

Каждый раз, когда вы выполняете $(a), он выполняет очень сложный набор операций, поэтому лучше его кешировать. Кроме того, вам не нужен заголовок, если система отличается. Эта версия должна немного ускорить ее:

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

Вы также можете кэшировать значения в объекте

Затем вместо:

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

делать:

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

Ответ 2

Вы должны переместить любые вызовы селекторов следующим образом:

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

из функции компаратора. Функция компаратора должна быть легкой.

Использовать children(), next() и т.п. или сканирование, которое вы установили один раз, и создать массив ключей вверх, а затем отсортировать его с помощью этих клавиш.

Функция компаратора будет называться 2n * ln(n) times (зависит от используемого алгоритма), где n - это количество элементов в наборе. Таким образом, ваш код делает как минимум два дорогостоящих вычисления.