Начнём с нашего любимого примера – простого (в одну колонку) списка рубрик из справочника предприятий vostsibspravka.ru: listru1.htm. Наиболее очевидный алгоритм отбора слов из списка такой:
На нашем списке (430 элементов) такая схема работает нормально, однако уже видно глазом, что при убирании класса hidchild отрисовка полного списка «подтормаживает» (пусть и на долю секунды, но заметно). Интересно, что измерение времени внутри javascript эту задержку показать не может (так как она возникает внутри другой подсистемы – CSS).
Возникает соблазн скрывать-отображать элементы каким-то другим способом. Например, не «условным», а прямым скрытием элементов. Делаем второй пример, в котором элемент списка не меняет своего поведения по отношению к дочерним (класс hidchild присвоен навсегда): listru2.htm. Алгоритм усложняется:
Перед началом работы предварительно (при открытии страницы) копируем весь список, присваиваем ему навсегда класс hidchild и в невидимом режиме (display:none) вставляем на страницу:
(Где invis_class = 'disnone', invis_child = 'hidchild')
Глазом видно, что при неуспешном поиске отображение всего списка происходит быстрее, чем в Примере 1. Хотя логирование времени работы показывает, что ищет второй скрипт медленнее, чем первый.
Всё, это предел. Быстрее напрямую работать с DOM (HTML-элементами) невозможно. Да и не нужно, если список маленький. А если большой, необходимо так называемое «кэширование»: например, помещение списка в пямять компьютера в виде javascript-массива (а не в виде DOM-дерева).
В первом приближении создать из HTML-элементов «виртуальный» список для поиска можно так:
Поиск в цикле по полученному массиву (warr) будет идти в разы (а то и в десятки раз) быстрее, чем по реальным HTML-элементам. Но что делать с найденными значениями? Они ведь никак не связаны с самими элементами списка. Значит, надо создавать как минимум два массива с одинаковыми индексами: один для поиска, а второй для выдачи элементов по найденным индексам.
В нашем усовершенствованном скрипте будет всё-таки один массив, но каждый элемент в нём является объектом с двумя значениями: текст для поиска (value) и элемент списка (html_el):
Теперь мы можем гораздо быстрее найти все элементы, в которых есть нужный текст.
Ещё одна проблема возникает, оттого что в цикле поиска мы обрабатываем все HTML-элементы: и полезные (найденные) и ненужные. Если в элементе есть искомый текст, назначаем элементу один класс, если нет текста – другой (точнее, добавляем и удаляем класснэйм vis):
И всё это в режиме реального времени, прямо с существующими на странице элементами.
Быстрее будет 1) обрабатывать только полезные элементы (а к ненужным вообще не обращаться), 2) собрать все найденные (полезные) элементы в один объект не на странице, а в новом, ещё не присоединённом к DOM элементе, и потом отобразить этот элемент сразу весь (а не по кусочкам).
Для этого в HTML-код страницы вставляем перед списком пустой (почти:-) элемент div (id = links2) – в этот элемент будем вставлять сгенерированный список элементов; перед началом поиска создаём новый элемент-контейнер для накопления найденных:
В цикле поиска складываем в контейнер полезные (содержащие искомый текст) элементы списка:
По окончании цикла присоединяем наполненный (или нет) контейнер к существующему на странице links2 и скрываем (или отображаем – в зависимости от успеха поиска) основной список links:
Как это всё вместе работает, можно посмотреть в примере listru3.htm (javascript – в файле listru3.js). Особенно заметны отличия (в скорости) от первого варианта listru1.htm на медленном компьютере, в каком-нибудь IE6. Да, и это ещё не предел. Список ведь может быть и не 400 строк, а 1400, или даже 14000; и не список, а целая таблица. Как ускорить поиск в этом случае, читайте в следующей статье.