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

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

Вот такая ситуация:

- У нас была огромная интерактивная таблица данных
- Под огромными я подразумеваю ~ 40 000 узлов в DOM
- Это означало ~ 5900 слушателей событий
- Или ~ 12 000 наблюдателей angular
- Это было огромно

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

Приложение может отображать строки данных на основе диапазона дат, запрошенного пользователем, поэтому в большинстве случаев многие пользователи запрашивают только короткий диапазон дат и, следовательно, не испытывают последствий наличия 40 000 узлов в DOM. Но для некоторых пользователей работа с данными в больших диапазонах дат была частью их работы (в общем, я имею в виду данные за 2 недели, что не кажется большим, но это с точностью до 5 минут!). Таким образом, для этих пользователей они испытывали вялый пользовательский опыт с простыми действиями при наведении / щелчке, которые занимали несколько секунд, тогда как они должны быть мгновенными.

Моей первой задачей было выявить любые красные флажки производительности в приложении, и я сделал несколько интересных выводов:

нг-шоу / скрыть

Некоторые из самых крупных компонентов приложения были скрыты за ng-show / hide. Это означало, что DOM все еще рендерил все свое содержимое, а angular компилировал все свои контроллеры / директивы, даже если пользователя это не интересовало.

Простая замена ng-show / hide на ng-if, где это возможно, значительно уменьшило количество узлов в DOM, тем самым уменьшив количество наших слушателей и наблюдателей.

стили svg

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

Кажется, что элементы SVG начинают терять свои преимущества в производительности, когда к ним применено слишком много стилей, плюс D3 (библиотека, которую мы использовали для передачи данных в наши SVG) не поддерживает делегирование событий элегантно, поэтому у нас были прослушиватели событий, прикрепленные к каждому один элемент SVG - буквально тысячи!

Я решил попробовать вернуться к HTML-элементам и обнаружил, что существенной разницы в производительности нет, доказывая, что из-за сложности нашей таблицы в SVG не лучше, чем в HTML. Хотя это был полезный вывод, он не должен был существенно повлиять на производительность нашего приложения, но, поскольку это приложение angular, я бы порекомендовал придерживаться HTML, поскольку было бы более удобно управлять нашими данными и событиями с помощью одна технология, а не смесь angular и библиотеки D3.

ng repeat track by

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

Я обнаружил несколько областей в приложении, где мы не использовали это, особенно в больших таблицах, поэтому мы были уверены, что добьемся некоторых улучшений, добавив его. Также стоит отметить, что ссылка на уникальный идентификатор объектов, которые вы повторяете, даст вам лучший прирост производительности по сравнению с использованием $ index. Так что, если у вас есть уникальный идентификатор или вы можете добавить его - это определенно стоит сделать!

бесконечная прокрутка

С того момента, как я приступил к выполнению этой задачи, я знал, что она, скорее всего, здесь и закончится. Огромный объем данных, который необходимо отображать по запросу, означает, что, несмотря на все значительные улучшения производительности, описанные выше, этого все равно будет недостаточно. Веб-приложения просто не могут обрабатывать такое количество элементов в DOM, независимо от того, насколько производительны все остальное.

Но приведенные выше улучшения были по-прежнему важны. Если мы перебираем сотни строк и не используем track by - мы делаем что-то не так. Если у нас есть огромный компонент, заполненный контроллерами и директивами, и мы не удаляем все эти потенциальные дайджесты - мы делаем что-то не так. Поэтому было важно, чтобы я решил эти проблемы, прежде чем приступить к единственному усовершенствованию, которое, будем надеяться, взорвет все и решит наши проблемы.

Идея бесконечной прокрутки довольно проста, но для ее реализации необходимо проделать большую работу. Он позволяет вам `` перерабатывать '' элементы DOM, которые находятся вне поля зрения, так что, когда пользователь прокручивает, чтобы запросить больше элементов, вы могли повторно использовать их, беря элемент сверху, когда он находится вне поля зрения, и используя его. для отображения следующего элемента внизу (и наоборот, если вы прокручиваете вверх).

Разработчики Google опубликовали отличную статью, объясняющую, как можно реализовать бесконечную прокрутку.

Заключение

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

В моем случае реализация описанных выше улучшений производительности - и особенно бесконечной прокрутки - уменьшила количество моих узлов до 7000 (вниз на 33000), наблюдателей до 1800 (-10200) и событий слушателей до 500 (-5400). Мы решили мои проблемы с прокруткой и перерисовкой, приложение стало намного более отзывчивым, и наши пользователи, наконец, смогли работать более продуктивно.

Существует ряд библиотек с бесконечной прокруткой, которые следуют принципам, упомянутым в статье Google выше. Один из них, который я бы порекомендовал, - это angular-vs-repeat, в первую очередь потому, что он легкий и просто обтекает ваш существующий ng-repeat, поэтому нет необходимости структурировать существующий код вокруг него, как некоторые другие библиотеки (и есть поддержка Angular 2!) .