Pull to refresh

Comments 84

Спасибо Vadyacorp за приглашение! Перенес статью из песочницы.
еще один минус сортировки на клиенте — вынос бизнес логики с сервера. как будете сортировать даты, например, если приложение поддерживает разные форматы?
ваш способ не подходит для реальных приложений.
Мой пример достаточно легко нарастить так, чтобы поддерживались разные форматы даты. При выводе ведь все равно известно, какой формат даты будет в колонке. Я бы сказал, что способ подходит для реальных приложений, но, конечно, не стоит пихать его направо и налево.
хм… при выводе это известно только на сервере. на клиенте — нет.
01/02, 02/01 — как вы на клиенте узнаете, в каком порядке должны следовать эти даты?
единственный способ — передавать используемый формат на клиента, что увеличивает связанность кода.
давно уже есть техника ajax, тут ей самое применение.
Автор писал «Плюсы — отсутствие перезагрузки страницы». AJAX, принимая во внимание факт, что реальная табличка весит в разы больше остального интерфейса, по сути — перезагрузка страницы.
ну ajax-ом же можно только массив данных передавать, а потом уже яваскриптом его разбирать — пересылаемых данных будет немного.
а если только яваскриптом — будет как на торрентах, т.е. в списке, разделёном на страницы, сортировка производится на текущей странице без учёта остальных.
что Вам мешает указать клиентской логике в каком формате дата?
появится (к примеру) переменная var dateFormat = 'm/d' (или d/m) и в зависимости от этого сортируем нужным способом (или мне Вам рассказать как преобразовать дату в JS?)
меня уже так за это мнение заминусовали, что мне уже страшно :)

вы правы, так можно сделать. но зачем иметь две логики и на клиенте и на сервере?
вообще, если нагрузки большие это полезно, еще я когда так делал, передавал 2 даты, одна для отображения, другая для сортировки, тогда хоть словами можно дату писать =)
А какая тут бизнес логика? Тут только представление информации.
что значит какая? правила сортировки — это бизнес логика («несложная»). представление информации — это вывод уже отсортированных значений.
хоть и допускается вынос несложной бизнес логики на уровень терминала, но по моему личному опыту это можно делать разве что на домашних страничках.
Вам понятно значение слова «бизнес»?
Сортировка — это не бизнес-логика.
да, мне понятно значение этого слова.

привожу пример: вывод списка документов (в сферической cms), отсортированных по статусу. сначала идут Draft, потом Work In Progress, потом Final. это бизнес логика. потому что при переводе на русский порядок не поменяется.
вы можете расширить этот пример на все случаи сортировки.

при разработке нужно всегда быть готовым к новым бизнес требованиям. а код, который тут приведен, к ним не готов.

если вы поняли, что я вам тут говорю, почитайте про трехуровневую архитектуру, хотя-бы тут ru.wikipedia.org/wiki/Трёхуровневая_архитектура
а если не поняли, то не утруждайтесь.
Приведенный пример некорректен. В теме обычная таблица, в которой данные равнозначны. Да и в вашем пример должна быть опция — по-другому сортировать.
В нашем приложении например пользователи сами могут для каждой таблицы настраивать свои сортировки, как им удобнее. Вы будете утверждать, что у наших пользователей разные бизнес-логики?
извините, я умываю руки.
хочется посмотреть на лицо нашего бизнес аналитика, когда я ей скажу сегодня, что сортировка — не бизнес логика.

завидую вам: вы живете в идеальном мире.
Гипотетический пример. Допустим один из ваших пользователей(если у вас веб-приложение) поставил себе какой-нибудь хитрый или плагин или скрипт GreaseMonkey, который позволяет сортировать таблички как ему хочется. Изменится ли как-нибудь лицо вашего бизнес-аналитика, когда она об этом узнает?
согласитесь, что такая сортировка в общем случае будет работать неверно, так как сторонний скрипт ничего не знает про структуру отображаемых данных.
в случае установки такого скрипта разработчики не несут ответственности за корректное отображение данных. кроме того, в требованиях к окружению обсуждаются эти вопросы.
представте себе аналитика (пользователь системы), который себе такой плагин себе поставил и отсортировал какие-нить хитрые рейтинги. его просто уволят, если он будет этим пользоваться.

реакция такова: если выяснится, что кто-то у клиентов ставит себе такую штуку, то каждый раз, когда они нам будут постать баг, первым вопросом будет: а не поставили ли вы себе каких-то плагинов.

таковы реалии.
Реалии действительно таковы. Это правда. Поэтому и пример был гипотетический :)
А если пользователь скопирует ваши данные в эксель и там будет сортировать — это случайно вашу бизнес-логику не затронет? Фактически мы имеем такой пример, что пользователь получил данные и хочет их смотреть так, как ему хочется. Всякие аналитики это любят очень(не которые «бизнес-», а другие).
Ну в общем ладно. спор пустой. Я просто считаю, что сортировать для удобства пользователя можно даже совершенно не представляя что за данные сортируем(все хорошие гриды это делать умеют). И в таком случае это уже нельзя назвать бизнес-логикой.
А можно поинтерисоваться где вы работаете? В какой компании в считают сортировку исключительно частью бизнес-логики приложения?
если интересно, то в личку
Уже давно распространено, что сортировка на сервере не вызывает перезагрузки страницы.
Не всегда есть необходимость посылать AJAX запрос на сервер. Бывают ситуации, когда нужно отстортировать на стороне клиента. Данные уже выбраны из базы, отправлены клиенту. Если он хочет лишь изменить сортировку, то почему не отсортировать без лишних запросов?
А если таблица слишком большая, что разбивается на несколько страниц?
Для этого, конечно, нужно перегружать страницу, либо дергать новый контент с помощью AJAX.
… «для этого»? то есть вы будете хранить в джава скрипте «размер» полученной таблички, и, если она меньше чем 200 строк, то сортировать джаваскриптом, а если больше, то аяксом?
а если постраничная навигация предусматривает 20- записей per page. то тогда что?
Можно сделать пейджинг таблицы посредством ДЖс или добавить тот же скролл (что бы заголовки таблицы оставались на месте), а дальше всё будет зависть от тонких-клиентов ;)
Однако ajax запрос всё равно требует реквеста и ожидания ответа. Кроме того, ответ нужно ещё обработать. И поэтому он тоже может занимать больше времени чем сортировка на клиенте. Поэтому вопрос остаётся.
Абсолютно верно, его функционала хватает за глаза. Есть возможность сортировать текстовые значения, числовые, даты, денежные единицы и тд. Свои парсеры, добавление виджетов и тд. Наличие кеширования, для ускорения сортировки (дом считывается только 1 раз)
code.google.com/p/dollar-script/source/browse/branches/jfix/base.js/string.js#23

hello
hello 2
hello 10
hello world
UFO just landed and posted this here
Смысл этой сортировки? Для сортировки данных в 50? 100? 200 записей? А если записей 1000? Тут мне кажется логичней через ajax подгружать json — передача по времени займет вовсяком случае меньше, чем перезагрузка страницы — но мы хоть получим адекватную сортировку по всем записям в бд.
Запрос к базе может быть «тяжелым». Конечно, применение такой сортировки должно быть оправдано.
Блин. Дело то не в том, на сколько быстро это сортируется. У меня есть 1000000000 записей в бд. Я говорю — хочу отсортировать данные по полю A. Что вы отсортируете своим скриптом? Записи от погруженных данных? Или вы собираетесь загружать все данные, а потом сортировать на стороне клиента?
p.s. Как вы надоели срать в карму. Прежде чем спускать карму — научитесь уважать чужие мнения.
зы: научился бы читать топики полностью, дальше заголовков
ззы: к твоей карме отношения не имею
Мне кажется, смысл как раз в сортировке таблиц с небольшим количеством данных. В этом случае получается и быстрее и удобнее.
>>> Этот метод очень быстрый

Не верю. Таблица 100 строк, 100 столбцов, думаю браузер надолго задумается.

Существенно оптимизировать можно здесь:

this.tBody.appendChild(dataCol[i][2]);


— добавление каждой строки у вас лезет в ДОМ. Это плохо. Лучше push-ем в масив загнать, а потом единожды в ДОМ засунуть.
Число столбцов в данном примере не влияет на производительность, т.к. я оперирую строками. Я проверял на 500 и 1000 строках, сортировка идет вполне сносно.

За идею оптимизации спасибо.
По поводу незадействованности столбцов не согласен — как не крути при вставке в ДОМ браузер каждую ячейку обрабатывает — а это время.

Я буквально вчера делал сортировку таблиц. При чем очень хитро. :) Задача была в том, чтобы сделать таблицу с 2-мя ФИКСИРОВАННЫМИ столбцами (как в екселе, если столбцов очень много, то прокручиваются все столбцы, кроме первых двух зафиксированных).

Следовательно, пришлось разбить таблицу на 2-е: одна на месте, другую прокручиваем. И, соответственно, «связывать» столбцы, и при сортировке одной таблицы, сортировать другую…

Также, для каждой ячейки есть парсер, так как не все что написано в ячейке нужно сортировать.

ИТОГО: около 100 строк, 20 столцов (что несущественно) — сортировка занимает на моей машине (2.2GHz, 2GB) — около 5-8 секунд!
Кстати, большинство браузеров применяют изменение ДОМа после выполнения функции. Об этом недавно писали тут
в случае аякса проблема с ДОМом останется.
Это:
var l = dataCol.length;
for(var i = 0; i<l; i++) {
  this.tBody.appendChild(dataCol[i][2]);
}

можно оптимизировать вот так:
var l = dataCol.length;
var fragment = document.createDocumentFragment();

for (var i = 0; i<l; i++) {
  fragment.appendChild(dataCol[i][2]);
}

this.tBody.appendChild(fragment.cloneNode(true));

В этом случае у нас происходит один appendChild и cloneNode для дом узла. Если я не прав поправьте пожалуйста
Я об этом и написал. Просто не равскрывал решение автору, а сказал где и как оптимизировать.
Вы частично правы, что appendChild для tBody происходит один. Но теперь то же самое время уходит на appendChild в fragment.

В IE8 профайлер показывает 234мс в обоих случаях.

Кардинально проблему это не решает.
А на каком количестве строк вы тестировали?
Скорее всего выигрыш будет, при увеличении числа строк до 1000…
И посмотрите в ие6, разницу вы заметите…

DocumentFragment — является облегченным контейнером для DOM-узлов.
appendChild для tBody != appendChild для fragment
одно дело когда происходит обращение каждый раз к дом модели, другое к памяти…

Так же можно использовать другой вариант:
this.tBody.innerHTML = html.join("");

где html это строковый элементов массив
Тестировал на 500 строках.

Ноды строк находятся в документе, при вызове fragment.appendChild(dataCol[i][2]) ноды перемещаются в fragment, т.е.
обращение к DOM всеравно происходит.

С innerHTML может получиться быстрее, но я не уверен что будет значительно. И еще придется делать костыль для IE, т.к. у него innerHTML для table и tbody только для чтения.

Сортировка 10 записей может быть реализована любым алгоритмом — даже самым неоптимальным. Было бы гораздо лучше, если бы Вы выложили пример Вашей сортировки для 4000 записей.

Когда-то давным давно у меня стояла задача сортировки данных у клиента. Я нашёл несколько скриптов, но все они были медленными, кроме одного единственного, который я и применил. Поэтому, хотелось бы оценить этот скрипт на больших объёмах данных. В противном случае, чем этот алгоритм сортировки отличается от десятков уже кем-то написанных?
Насколько я понимаю тут используется встроенный sort в javascript. Думается что он реализует qsort и работает быстро.
Обычно табличную информацию выводят с разбивкой на страницы, а сортировка должна сортировать данные по всем страницам. Поэтому метод на реальных задачах не применим, разве что вы загрузите всю таблицу в какой-то локальный кэш и в дальнейшем будете работать только с ним, но даже тогда передача всей таблицы из БД может перекрыть выгоду от локальной сортироки.
Плюс к этому память, выделяемая на сервере для выборки всех записей может неожиданно закончиться, когда объём данных перевалит за пару тысяч значений.
А если бить выборку из базы по страницам, то это ничем не отличается от запросов к серверу с выборкой ограниченного объёма.

Скорее всего, сортировка на клиенте нужна в небольших таблицах. В больших — обращение к серверу, на котором выборки кэшируются.
UFO just landed and posted this here
Большое спасибо! Давно искал простые способы реализации. И очень понятный пример.

Я не понимаю, к чему придирки некоторых комментаторов? Пример хороший, наглядный. С возможностью доработки прямыми ручками. То, что он не универсален никак не умоляет его достоинств.
Главное здесь — идея и реализация. Автор поделился, а те, кому это интересно — взяли на заметку.
Имеющие более другие варианты — пишите, статей много не бывает.
К минусам клиентского варианта также относится невозможность работы с большими массивами данных.
Приведенный в статье минус серверного варианта решается использованием асинхронного javascript
Спасибо, очень интересно.
Теперь есть из чего выбрать. Искал подобные реализации.
frequency-decoder всегда писал чудные скрипты, реально есть чему поучится ;)
Обычно таки в реальных проектах таблицы многостраничные, то есть в данный момент на экране только часть данных.

Но все равно — вполне достойное решение со своей областью применимости.
Вполне хорошее решение. Критики этой статьи, в своих ответах утверждают, что сортировку лучше делать на сервере. Пожалуй они правы для веба, но есть еще и десктопные приложения сделанные на технологии AIR, и для них вполне отличное решение. :)
Спасибо.
Странно, что у вас в десктопном AIR приложении не было сортировки таблиц.
Невероятно мощный и надежный плагин jQuery для сортировки таблиц — http://www.datatables.net пользуюсь активно и продолжительно, лучше еще не видел. Настраивается буквально все, документация на уровне, активно развивается.
Действительно хорошая вещь :) Сам хотел такое писать, а теперь уже и не надо :) приятно.
У этого плагина есть ещё одна особенность — он умeет искать в таблице по введённому регулярному варажению, выводя только подходящие строки.

улыбнуло
при сортировке ноды таблицы переставляются только в конце посредством последовательного вызова appendChild.
А известно ли Вам, уважаемый автор, что каждое обращение к DOM настолько ресурсоемко, что даже вместо 10 элементарных изменений лучше сделать 1 комплексное? И еще мне кажется, что while(i--) вкупе с внутренним сравнением будет побыстрее сортировки массива таким способом. Если у кого будет время на написание тестов и сравнение браузеров, буду весьма признателен.

P.S. на тему быстродействия можно почитать блог YASS — habrahabr.ru/blogs/yass/
Про скорость работы с DOM я в курсе.

На данный момент 100 строк переставляется за 100 вызовов appendChild. Скажите пожалуйста, как существующие ноды строк Вы предлагаете комплексно переставить согласно порядку в массиве, чтобы число операций с DOM был существенно ниже?
очевидно же: полностью переписав исходный элемент. Если мы будем содержать подготовленный JS-массив, который будет включать все данные из таблицы. А на основе этого массива будет строить саму таблицу динамически — дело намного быстрее пойдет.
Да, но это совсем не решение задачи сортировки уже существующей таблицы.

Вот — оптимизированная версия с 500 строками в качестве примера.

Скорость сортировки вполне удовлетворительная.
в смысле? У нас есть таблица на странице, мы ее сортируем. Какая разница конечному пользователю, что у нас там на странице еще напихано?

А про «удовлетворительно — неудовлетворительно» писать не стоит, если у Вас топик направлен на решение как раз проблемы быстродействия. Т.е. тут Вы сами себе немного противоречите, когда сначала заявляете, что «данное решение самое быстрое», а потом «но скорость его работы удовлетворительная».
Хорошо, спрошу иначе.

Есть дерево DOM. В нем есть 100 нод. Как изменить порядок этих нод относительно друг друга используя много меньше 100 операций с нодами?
если предполагается, что у нас нет никакого массива в JS, то предложенный метод «вставочной» сортировки — самый быстрый. Но в условиях, что DOM-операции крайне дорого обходятся, его применении стоит под большим вопросом (DOM вообще использовать не стоит).
Да, я согласен. Всему есть свое применение. Поэтому я считаю, что метод, описанный мной имеет место быть в некоторых ситуациях. Внедрение будет «малокровным» и для сравнительно небольших таблиц — самое оно.
да, с этим полностью соглашусь. Просто хорошо бы в самом начале тогда вставку давать, где метод применим и почему.
Сортировать js можно только если таблица умещается полностью на 1 странице.
Это было почти верно до появления новых версий браузеров. Сейчас Javascript очень сильно ускорился, и сортировка работает достаточно быстро. Таблица 1500 x 15 сортируется за одну — две секунды, причём это алгоритм трёхлетней давности.
Да, но получается, что ее всю сначала нужно загрузить в тело страницы… хотя сейчас и инет быстрый :).
если грузить таблицы в JSON формате, да ещё паковать gzip' ом — очень быстро получается.
Да я вроде б и не пытаюсь уговорить, что это плохо :) — всему есть применение. При больших объемах таблицы я б пользовался аяксом (1500+ строк), при средних кол-вах можно оба варианта проработать, а при мелких таблицах (100-25 строк) однозначно js.
Статью я бы назвал как-нибудь вроде «Учимся применять функцию Array.sort в javascript», а не более претензионное «Быстрая сортировка таблиц посредством Javascript» (которая больше подходит, если бы вы здесь дествительно расписали какой-то новый алгоритм сортировки на javascript).

Далее, Array.reverse для обращения результатов сортировки это… это как минимум мне не понятно.
Что мешает сделать как обычно?

function MySort (items, sortDirection)
{
if (!items)
return;

var sort_direction_multiplier = sortDirection? 1: -1;

items = items.sort(function(a, b)
{
if (a > b)
return sort_direction_multiplier;
else if (a < b)
return -sort_direction_multiplier;

return 0;
});

return items;
}

(может где в синтаксисе напутал — но суть понятна)

На счёт сторонников сортировки на сервере — это не всегда оправданно. Если таблица заведомо не сильно большая, то можно выдать клиенту все данные (к примеру, через тот же Ajax и gzip) и дать инструменты для работы (сортировка/фильтрация) прямо на клиенте. Для клиента это будет гораздо приятнее. Правда это уже всё мелочи и дело вкуса разработчика, по большому счёту.

На счёт тех, кто говорил, что если запрос очень сложный — в этих случаях сначала выбираются id-шники а уж потом с ними работают (разбивают на странице и при выборке не забывают, что нужно сохранять порядок следования результатов согласно порядку переданных id-шников).
Array.reverse используется, чтобы не использовать обработчик для текстовых колонок. К томуже она работает быстро.
Какая версия Firefox? После чего зависло?

Очень странно.
3.5.3

завис после того, как нажал на сортирование одного из столбцов ине дождавшись пока отсортирует, начал клацать снова на сортировку. после где-то 10ти кликов FF завис.
сейчас ещё раз попробовал — всё отлично работает. странно.
UFO just landed and posted this here
Sign up to leave a comment.

Articles