В свое время я прибывал в уверенности, что код
js обычно не нужно писать так, чтобы он был
наиболее оптимальным. «Клиентская часть» — говорил я, — «на сервер никак не
повлияет, а посему, можно забить». К сожалению, оказалось, что это не совсем
так.
Данная статья содержит технические сведения. Если вы не понимаете о чем здесь написано, пожалуйста, не минусуйте.
Началось все с использования библиотеки
EXT JS на нашем проекте, а
конкретно – виджета EditableGrid. Первоначально
библиотека очень понравилась. Прежде всего своей объектно-ориентированной
структурой. Проблемы начались позже. Забегая вперед скажу, что я все еще
остаюсь поклонником EXTJS. Другой библиотеки, которая была бы такой же
логичной и предлагала такие возможности я не знаю. Кроме того, следует
отметить, что очевидные проблемы с производительностью начинались либо при
большом количестве колонок в таблице, либо при большом количестве строк (про
это разработчики библиотеки, впрочем, предупреждали).
Про некоторые общие проблемы js вы можете прочесть здесь
CSS — CascadingStyleSheets – “а для чего слово
каскадные?”
На самом деле, на эту проблему мне указал наш
html кодер (Женя, привет!
J)
Взгляните на css файл,
который используется.
Да, иногда стили специфицируются каскадно, но в
подавляющем большинстве – НЕТ. «В чем же проблема» — спросите Вы. Для меня,
как для программиста на java, проблемы не
существовало до тех пор, пока я не внедрил грид на отверстанную страницу. И…
у меня поплыли все стили. Грид выглядел ужасно. В чем дело? Дело в том, что на
странице использовался общие css стили для всего
проекта и они имели приоритет выше, чем те стили что описаны в
grid.css. Почему
так – я Вам не объясню. Я понимаю это как «чем точнее задан путь, тем выше
приоритет у стиля», по крайней мере такой объяснение для меня работает. Есть
еще модификатор «!important», но как мне рассказали, этим лучше не
злоупотреблять. Надеюсь, учитывая количество профессиональных дизайнеров
здесь, в комментариях будет объяснение.
Итак, для себя я сделал вывод – использовать слово
«каскадные» в определении CSS.
Обновление CSSправил или первые тормоза
Вышло так, что по требованиям в одном из гридов нужно
было отображать 20 колонок. «Небольшая цифра» — как я думал. Оказалось, что
нет.
Ext.grid.GridViewиспользует забавный механизм для указания ширины колонок. При отрисовке
создается узел <style> в который
записываются пустые стили вида:
#[идентификатор грида]
.x-grid-col-[номер
колонки] {
2}
Например:
#grid-example .x-grid-col-0 {
2}
Когда html код готов,
происходит изменение этих динамически сгенерированных стилей и указывается
ширина каждой колонки. Для каждого такого стиля выполняется
Ext.util.CSS.updateRule
Надо сказать, что это не дешевая операция. А для 20ти
колонок наблюдались заметные тормоза. Таким образом пришлось оптимизировать
этот механизм, чтобы убрать ощутимую паузу, которая происходила с момента
загрузки, до того момента, когда пользователь мог реально что-то сделать.
Кроме того, загрузка процессора была 100%.
Первоначально я генерировал не пустые стили, а сразу
создавал заполненные с установленными значениями ширины
(width). Прокатило, но потом и это пришлось
убирать (см. ниже).
Итак, для себя я сделал вывод – не использовать
динамическое обновление таблиц CSS.
Большое количество элементов или «ну сколько можно
пихать?»
Примерно такой код Вы увидите для каждой ячейке в
гриде:
<td class=«x-grid-col x-grid-td-1
x-grid-cell-5-1» tabindex=«0»>
<div class=«x-grid-col-1
x-grid-cell-inner»>
<div class=«x-grid-cell-text» unselectable=«on»>$31.61</div>
</div>
</td>
Это только ОДНА ячейка. Получается, что кроме
td, несчастному броузеру нужно будет держать еще
как минимум два DOM объекта. Это занимает память
и ресурсы.
На мой взгляд, этого нужно избегать.
Работа с DOMтаблицей или «ну вот оно и умерло»
Надо отметить, что на форумах разработчики честно
предупреждают о том, что работа с большим количеством строк будет тормозить и
следует использовать разбивку на страницы. Но… пользователи всегда правы и
страницы видеть не захотели. На самом деле, существует простой способ
оптимизировать грид для работы с довольно большим количеством строк (у меня
работает с 500 без тормозов).
Какая была проблема? Дело в том, что
GridView для представления использует таблицу.
Операции по удалению/вставке/редактированию работали очень медленно, если
количество строк было больше 20 (при количестве колонок больше 15ти). Оно и
понятно, таблица – это не просто массив, а целый объект, которые нужно
пересчитать/перерисовать. Кроме того, при изменении всех значений в какой-либо
колонке (например, вычисляемая колонка, которая зависит от внешнего параметра)
броузер просто умирал и в себя уже не приходил.
Как это решилось? Из профайла я понял, что работа с
большими таблицами (> 20-30 строк) занимает на порядок больше времени, чем
с маленькими (< 20 строк). После этого я глянул на реализацию
Google Spreadsheet. Вот
что я там обнаружил: они не используют одну большую таблицу, а разбивают на
много маленьких, которые располагаются одна под одной. Кроме того, ширина
колонок задается не стилями, а, что более логично, через ширину первой строки
с использованием стиля
table-layout:
fixed.
Результат
Таким образом, GridViewбыл переписан с учетом следующих правил:
— Использовать КАСКАДНЫЕ стили
— Не добавлять лишних элементов в
DOM
— Не использовать динамическое обновление стилей
— Разбивать большие таблицы на несколько
маленьких
В результате я получил
EditableGrid, который может работать с большим
количеством строк.
js обычно не нужно писать так, чтобы он был
наиболее оптимальным. «Клиентская часть» — говорил я, — «на сервер никак не
повлияет, а посему, можно забить». К сожалению, оказалось, что это не совсем
так.
Данная статья содержит технические сведения. Если вы не понимаете о чем здесь написано, пожалуйста, не минусуйте.
Началось все с использования библиотеки
EXT JS на нашем проекте, а
конкретно – виджета EditableGrid. Первоначально
библиотека очень понравилась. Прежде всего своей объектно-ориентированной
структурой. Проблемы начались позже. Забегая вперед скажу, что я все еще
остаюсь поклонником EXTJS. Другой библиотеки, которая была бы такой же
логичной и предлагала такие возможности я не знаю. Кроме того, следует
отметить, что очевидные проблемы с производительностью начинались либо при
большом количестве колонок в таблице, либо при большом количестве строк (про
это разработчики библиотеки, впрочем, предупреждали).
Про некоторые общие проблемы js вы можете прочесть здесь
CSS — CascadingStyleSheets – “а для чего слово
каскадные?”
На самом деле, на эту проблему мне указал наш
html кодер (Женя, привет!
J)
Взгляните на css файл,
который используется.
Да, иногда стили специфицируются каскадно, но в
подавляющем большинстве – НЕТ. «В чем же проблема» — спросите Вы. Для меня,
как для программиста на java, проблемы не
существовало до тех пор, пока я не внедрил грид на отверстанную страницу. И…
у меня поплыли все стили. Грид выглядел ужасно. В чем дело? Дело в том, что на
странице использовался общие css стили для всего
проекта и они имели приоритет выше, чем те стили что описаны в
grid.css. Почему
так – я Вам не объясню. Я понимаю это как «чем точнее задан путь, тем выше
приоритет у стиля», по крайней мере такой объяснение для меня работает. Есть
еще модификатор «!important», но как мне рассказали, этим лучше не
злоупотреблять. Надеюсь, учитывая количество профессиональных дизайнеров
здесь, в комментариях будет объяснение.
Итак, для себя я сделал вывод – использовать слово
«каскадные» в определении CSS.
Обновление CSSправил или первые тормоза
Вышло так, что по требованиям в одном из гридов нужно
было отображать 20 колонок. «Небольшая цифра» — как я думал. Оказалось, что
нет.
Ext.grid.GridViewиспользует забавный механизм для указания ширины колонок. При отрисовке
создается узел <style> в который
записываются пустые стили вида:
#[идентификатор грида]
.x-grid-col-[номер
колонки] {
2}
Например:
#grid-example .x-grid-col-0 {
2}
Когда html код готов,
происходит изменение этих динамически сгенерированных стилей и указывается
ширина каждой колонки. Для каждого такого стиля выполняется
Ext.util.CSS.updateRule
Надо сказать, что это не дешевая операция. А для 20ти
колонок наблюдались заметные тормоза. Таким образом пришлось оптимизировать
этот механизм, чтобы убрать ощутимую паузу, которая происходила с момента
загрузки, до того момента, когда пользователь мог реально что-то сделать.
Кроме того, загрузка процессора была 100%.
Первоначально я генерировал не пустые стили, а сразу
создавал заполненные с установленными значениями ширины
(width). Прокатило, но потом и это пришлось
убирать (см. ниже).
Итак, для себя я сделал вывод – не использовать
динамическое обновление таблиц CSS.
Большое количество элементов или «ну сколько можно
пихать?»
Примерно такой код Вы увидите для каждой ячейке в
гриде:
<td class=«x-grid-col x-grid-td-1
x-grid-cell-5-1» tabindex=«0»>
<div class=«x-grid-col-1
x-grid-cell-inner»>
<div class=«x-grid-cell-text» unselectable=«on»>$31.61</div>
</div>
</td>
Это только ОДНА ячейка. Получается, что кроме
td, несчастному броузеру нужно будет держать еще
как минимум два DOM объекта. Это занимает память
и ресурсы.
На мой взгляд, этого нужно избегать.
Работа с DOMтаблицей или «ну вот оно и умерло»
Надо отметить, что на форумах разработчики честно
предупреждают о том, что работа с большим количеством строк будет тормозить и
следует использовать разбивку на страницы. Но… пользователи всегда правы и
страницы видеть не захотели. На самом деле, существует простой способ
оптимизировать грид для работы с довольно большим количеством строк (у меня
работает с 500 без тормозов).
Какая была проблема? Дело в том, что
GridView для представления использует таблицу.
Операции по удалению/вставке/редактированию работали очень медленно, если
количество строк было больше 20 (при количестве колонок больше 15ти). Оно и
понятно, таблица – это не просто массив, а целый объект, которые нужно
пересчитать/перерисовать. Кроме того, при изменении всех значений в какой-либо
колонке (например, вычисляемая колонка, которая зависит от внешнего параметра)
броузер просто умирал и в себя уже не приходил.
Как это решилось? Из профайла я понял, что работа с
большими таблицами (> 20-30 строк) занимает на порядок больше времени, чем
с маленькими (< 20 строк). После этого я глянул на реализацию
Google Spreadsheet. Вот
что я там обнаружил: они не используют одну большую таблицу, а разбивают на
много маленьких, которые располагаются одна под одной. Кроме того, ширина
колонок задается не стилями, а, что более логично, через ширину первой строки
с использованием стиля
table-layout:
fixed.
Результат
Таким образом, GridViewбыл переписан с учетом следующих правил:
— Использовать КАСКАДНЫЕ стили
— Не добавлять лишних элементов в
DOM
— Не использовать динамическое обновление стилей
— Разбивать большие таблицы на несколько
маленьких
В результате я получил
EditableGrid, который может работать с большим
количеством строк.