В Интернете существуют десятки скриптов для сортировки HTML таблиц. Большинство из них из года в год повторяют одни и те же ошибки в алгоритмах и в интерфейсе. Возможно, из-за этих постоянных ошибок пользователи до сих пор недооценивают удобство работы с данными на стороне клиента.

javascript сортировщики, сравнение алгоритмов

Всякое сравнение хромает в пользу того, кто сравнивает.

Попробуйте поискать в сети страницы по фразам «Сортировка HTML таблиц», «javascript сортировка», «table sorter»... Можно найти немало решений, но после первого же беглого анализа их удаётся свести к 5-7 более-менее внятным проектам. К сожалению, в основном, буржуйским (наши предпочитают переделывать чужое).

1. Neil Crosby, http://www.workingwith.me.uk/articles/scripting/standardista_table_sorting, 19 K, 2006

Код довольно приятный на вид, какой-то уютный. Например, начинается он с функции init, в конце которой вызывается функция run. И что бы вы думали – тут же следом идёт и сам текст функции run. И так всё и дальше – по цепочке, очень удобно и понятно.

2. frequency-decoder.com, http://www.frequency-decoder.com/2006/09/16/unobtrusive-table-sort-script-revisited, 20 K, 2006

Дистрибутив более-менее удобный, таблица выглядит не такой "черновой", как у соседей.

3. Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/, 16 K, 2007

Идеальная инструкция по подключению:

Код выглядит похуже, чем у Нейла Кросби: много длинных повторяющихся конструкций вида "cell.className.replace", "sortfwdind.parentNode.removeChild", много уровней вложенности...

4. Matt Kruse, http://javascripttoolbox.com/, 30 K, 2007

Много комментариев, но подключить не удалось (инструкция путаная). Код менее понятный, начинается с функции определения типов сортировки, потом вдруг совершенно отдельная функция Table...

5. Christian Bach, jquery TableSorter + jquery Pager, 80 K, 2007

Это типа "классика". Отличается надёжностью и огромным размером кода. Код самого сортировщика, правда, вполне приличный (23 K), но к нему ведь прилагается обязательная гиря в виде jQuery, да ещё и Paginator надо отдельно подключать...

6. Michael Leigeber, TinyTable v3, 7 K, 2009

Практически идеальный по сравнению со всеми остальными. Правда, в IE подготовка сортировочного массива растягивается на десятки секунд. Ну, и код чрезмерно "ужат", плохо читаем: полно строк вида "t.a[i].o=i; var v=t.r[i].cells[t.y];".

7. Michael Gutentog, Big Table Sorter v1.01, 21 K, 2011

Наш идеал. Во всех отношениях. Во-первых, просто скорость работы. Сравните:

  1. http://ir2.ru/static/sorters/fd/
  2. http://ir2.ru/static/sorters/la/
  3. http://ir2.ru/static/sorters/standardista/

Гм... ну, этих можно сравнивать только с Simple Table Sorter v0.03, 7.8 K, чтобы условия были более-менее равными (отсутствие постраничного вывода принципиально ограничивает скорость работы сортировщиков).

А вот сравнение в самой большой весовой категории:

  1. tiny
  2. jSorter
  3. Big Table Sorter v1.01

Во-вторых подключение и использование. Единственный недостаток нашего скрипта – нельзя настраивать разное отображение для отдельных таблиц на одной странице (настройки "глобальные"). Но вряд ли кто-то будет использовать больше одной таблицы в 2000 строк на одной HTML-странице (а скрипт рассчитан именно на большие объёмы). И недостаток обеспечивает достоинство – предельно простое подключение и управление: просто добавить в HEAD скрипты и CSS, просто указать (а можно и не указывать) типы данных для отдельных столбцов таблицы.

У конкурентов же надо обязательно инициировать сортировщик в отдельном фрагменте javascript-кода. Кроме того, jSorter, например, совершенно независим от jPaginator'a. Это, типа хорошо (изолированный, несвязанный код), но подключать всё вместе замучаешься (мне просто повезло – нашёл где-то готовый пример). В jSorter'е, к тому же, отсутствует система поиска значений по столбцам. Возможно, для jQuery есть какой-то плагин, но нам что теперь, по всему огороду метаться, чтобы собрать более-менее приемлемую систему работы с таблицей? Ближе всего к идеалу в этом плане TinyTable, но, во-первых, тоже надо инициировать сортировщик в JS, а главное (общий недостаток с jSorter'ом), управление постраничным выводом и фильтрацией данных при подключении надо рисовать в HTML самому! Вот уж воистину "удобства во дворе".

Мы неоднократно говорили, что для больших таблиц постраничный вывод и фильтрация данных – неотъемлемые части управляющего таблицей скрипта, без них работа с большими объёмами попросту невозможна. И наш скрипт самостоятельно, без участия пользователя (программиста) подрисовывает на страницу все необходимые HTML элементы: листатель страниц и поля ввода для поиска (отбора данных) по столбцам.

В "почти идеальном" TinyTable, на наш взгляд, всё-таки фильтрация данных сделана неудобно. Там одно поле ввода и выбор колонки, в которой надо искать. А при попытке искать по второй колонке, результаты предыдущего поиска сбрасываются. У нас же вся эта работа построена "полностью идеально": вводите символы для поиска в поля любой колонки, всё будет учитываться и сохраняться.

Мелкие удобства

Мы постоянно работаем над тем, чтобы получать данные из таблицы было удобно. В последней версии Big Table Sorter по рекомендации AleXH, добавлены два содержательных изменения в интерфейс:

  1. В заголовок таблицы добавлены "альтернативные" стрелки указания сортировки (их вид можно указывать в настройках) – они могут быть не просто указателями направления, но и в виде чисел, обозначающих порядок сортировки столбцов.
  2. Столбцы и строки при сортировке подсвечиваются особым образом, зависящим от содержания строк и порядка сортировки (алгоритмы описаны в статье tabsort1_01.aspx).

Про такие мелочи, как листание страниц по Ctrl + Right (как в Яндексе), я уже и забыл (но они всё равно работают). Или, допустим ведение логов с отображением времени сортировки (и подготовки). И это не предел (работа идёт дальше).

Алгоритмы

Тут надо писать целую поэму. В первой версии TinySorter'а (M.Leigeber) мы нашли подсказку – как сделать хак для ИЕ, ускоряющий создание сортировочного массива в десятки раз (с использованием банального cloneNode). Парадокс, но в последней версии TinyTable в ИЕ всплыла та же старая проблема – 20 секунд на создание начального массива. Может, конечно, проблема от другого, но разбирать код там очень сложно.

Создание массива – не самая затратная часть, все сортировщики более-менее с ней справляются (пришлось подправить с помощью "хака cloneNode" только standardista, иначе у вас бы не хватило терпения ждать загрузки таблицы в ИЕ). Не знаю, как они справляются, может другими хаками.

Вторая песня поэмы – это собственно сортировка. Самый "некрутой" случай тут – когда в пользовательскую функцию сортировки пихают распознавание типов данных. Ясно ведь, что функция, которая будет вызываться в цикле предположительно десятки тысяч раз (сколько надо операций сравнений, чтобы отсортировать 2000 элементов?), должна быть предельно проста. В идеале – просто rarr.sort(), и всё! Но если уж вы от большой нужны начали писать rarr.sort(cmp), то в cmp совершенно не следует пихать всякие if parseFloat(a[1]). Наиболее "точно" в этом плане построен jSorter: функция cmp там генерируется по условиям типа данных столбца (и некоторым другим) в насколько возможно простом виде. Мы никогда не против позаимствовать у конкурентов что-то хорошее, и в нашем сортировщике функция cmp генерируется примерно так же.

Примечательный куплет в песне о создании массива (или о сортировке – у менее продвинутых разработчиков :-)) – собственно распознавание типов данных. Вызывает умиление тщательность, с которой буржуи переписывают друг у друга парсеры (разных!) валют. Хотя при некотором участии мозга легко увидеть, что валюта не должна быть отдельным типом данных. Необычные типы (для которых нужны специальные парсеры) – это даты и ip-адреса. Валюта – это просто число. То есть мы (например, получив указание в заголовке столбца) должны рассматривать валюту как число: просто "ободрать" все не-цифры и врубить parseFloat. Зачем нам знать, доллары там или фунты?

В нашем сортировщике валюта и так сортируется как число, если указатель валюты стоит в конце. Если в начале – достаточно указать в заголовке таблицы <th axis='num'>, и сортировка будет корректной для любой валюты. jSorter использует авто-распознавание типов по первой строке, что является достаточно рискованным способом. Мы всегда приводим все типы к одному – к строковому (фиксированной длины, если реально там число).

Ни один из приведённых сортировщиков (кроме jSorter'а и нашего) не учитывает баг "не-гекко" браузеров – лишнюю сортировку рядов с одинаковыми значениями. Откройте любой пример таблицы выше и посмотрите: изначально данные отсортированы по первому столбцу (ИД). Щёлкните теперь, например, по столбцу width – вы увидите во 2-4 строках этого столбца одинаковые значения "145", а в первом столбце в этих же строках – "355", "828", "404"! То есть при одинаковых значениях в сортируемом столбце, всеми браузерами (кроме ФФ) порядок строк произвольно меняется! Этот баг в нашем Big Table Sorter'е обнаружил всё тот же AleXH (пора уже его брать в соавторы! :-)).

В последней части поэмы – отображении нового порядка строк после сортировки – нет, пожалуй, ничего примечательного. Тут не спасают никакие хитрости, если нет постраничного вывода. А вот в его организации есть один фокус. Наш сортировщик выводит большие таблицы быстрее всех (это, к сожалению, нельзя измерить с помощью js). На таблицах больше 4-5 тысяч строк это хорошо видно невооружённым глазом. Фокус простой: мы изначально не отображаем целую таблицу (и не заставляем браузер пытаться её вывести, пока идут вычисления размера страницы). У нас сразу в css для сортируемых таблиц стоит правило: .sortable tbody {display:none;}, а отображается только вычисленная страница высотой в 20 строк (по умолчанию).

Развитие проекта

Не знаю, как у других сортировщиков, но, по-моему, там давно уже никто не реагирует на замечания пользователей. В нашем же сортировщике – кому не хватает каких-либо функций, пишите в комментарии или на адрес stopkran@inbox.ru, как показывает практика, большинство пожеланий выполнить удаётся, пока что система открыта для изменений.

D.M., admin

Комментарии