Автор этой статьи: Жэнь Цзяле
Исходное заявление: Эта статья подготовлена членами команды интерфейса чтения YFE, пожалуйста, уважайте оригинальность, пожалуйста, свяжитесь с общедоступной учетной записью (id: yuewen_YFE) для авторизации и укажите автора, источник и ссылку.
буря производительности
«Говорят, что иногда в тропических лесах Амазонки бабочка, несколько взмахивая крыльями, может вызвать торнадо в Техасе через две недели», когда начальная точка страницы подписки также испытала аналогичные атаки торнадо, бабочка, которую мы обработали флажок (флажок). Мы не загрязняем окружающую среду Флажок Что именно было сделано, что привело к производительности этого шторма?
Перед бурей
Страница подписки отправной точки — это место атаки торнадо, и это также объект этой статьи. Я до сих пор помню, что разработка и совместная доводка «Лица-воспоминания, смотрящего вдаль» в то время шли гладко, и казалось, что «сюрприз» можно запускать немедленно. Однако после теста стиль рисования резко менялся, и тестируемые студенты бросали несколько блокбастеров.Когда количество глав на странице подписки превышало 3000 глав, возникали такие явления, как зависание, приостановленные страницы и сбои браузера. Когда я увидел эти баги, у меня замерло сердце.Сцены сверхдлинных работ с более чем 3000 глав действительно были проигнорированы в процессе совместной отладки.В любом случае быстро передвигайте кирпичи и "разбивайте морду"
Кстати, упомяну основную функцию страницы подписки: отображать все платные главы книги, а также подписаться на одну главу, один том и несколько томов, установив флажок.При инициировании операции подписки она также обеспечивает баланс оплаты, быструю оплату и функции контроля рисков.
сцена бури
Я нашел время, чтобы испытать страницу подписки «Создание фермы с помощью фермы», которая составляет почти 7000 глав от отправной точки Я пробормотал «Кто бы стал читать такую длинную статью», но я честно ответил на 3 очевидных вопроса:
1. Время загрузки области контента слишком велико
количество глав | Время загрузки (с) |
---|---|
3000 | 6.519 |
5000 | 14.732 |
7000 | 24.753 |
▲ Отметка времени печати получается путем усреднения результатов 10 экспериментов.
2. Убедитесь, что ответ флажка медленный.
3. Полоса прокрутки застревает при перетаскивании страницы
Проблема очень серьезная, и оптимизация производительности обязательна!
Анализ и разрешение аварий
Во-первых, старая версия элементов управления пользовательского интерфейса вызвала катастрофу.
Chapter 7000 Data Loading 24s "Извините?" По старой привычке сразу переходим к циклу кода, чтобы найти причину. Перед этим поговорим о логике отрисовки страницы подписки:
- Запрос данных главы после страницы DOM Ready
- Запрос шаблона EJS и визуализация шаблона EJS
- Вставьте отрендеренный шаблон в DOM страницы.
- Инициализировать экземпляр флажка
После захвата пакета запроса 250 КБ занимает 493 мс.Видно, что узким местом является не запрос данных, поэтому тест производительности шагов 2, 3 и 4 выполняется с локальными данными, и результаты следующие:
количество глав | Рендеринг шаблонов EJS | Вставка DOM в шаблоны EJS | Инициализировать экземпляр флажка |
---|---|---|---|
3000 | 92ms | 75ms | 6345ms |
5000 | 149ms | 133ms | 13948ms |
7000 | 278ms | 301ms | 23866ms |
▲Количество симуляций: 10
Приведенные выше данные показывают, что создание экземпляра компонента пользовательского интерфейса Checkbox является наиболее трудоемкой частью. Поскольку данные представляют собой базовую структуру, состоящую из книжных томов, для создания экземпляра одного флажка и с учетом требований к работе всего тома сначала необходимо выполнить цикл для тома, а затем для всех глав в томе, что имеет двухслойный цикл. Кроме того, согласно визуальным требованиям страницы подписки, если она совместима с IE7, нельзя использовать собственный компонент Checkbox, поэтому выбирается компонент пользовательского интерфейса Checkbox с лучшей совместимостью. Взгляните на код:
var chapter;
for (var v = 0; v < volumeNum; v++) {
//do something with book volume
for(var c = 0; c < volChapters.length; c++){
//初始化章节相关checkbox
chapter = new Checkbox({
selector: '#' + volChapters[c].id
});
//do something with book chapter
}
//do something after init checkbox
}
После печати метки времени я обнаружил, что инициализация компонента Checkbox занимает много времени, я попытался убрать логику инициализации компонента пользовательского интерфейса Checkbox и вместо этого использовал компонент пользовательского интерфейса LULU UI, который мы настроили для бизнеса с помощью CSS. чтобы постепенно увеличивать и уменьшать компонент украшения Checkbox, и ситуация действительно улучшилась. , результат выглядит следующим образом:
▲ Общее время успешного запроса данныхПо сравнению с предыдущими 24сами время загрузки резко упало до 1,925са (длина + длина логического представления о успехе данных запроса) с учетом различных сетевых сред, реальная ситуация должна быть больше 2s. Перетащите бар прокрутки CATON, но все же существует.
Продолжим!
2. Расширенные свойства CSS3 — палка о двух концах
Попробуйте поставить галочку "Выбрать все главы", ответ все еще задерживается, а время рендеринга достигло 5840,9 мс! Страница все еще застряла, и «схлопнувшееся лицо» все еще очевидно, продолжайте заполнять дыру!
▲ Установка флажка «Выбрать все главы» требует времени для рендеринга.Установка флажка «Выбрать все главы» делает только одну вещь: перебор всех флажков для изменения состояния пользовательского интерфейса и получения свойств. Хотя LULU UI использует свойства CSS3 для отрисовки Checkbox, не вызовет ли это таких серьезных проблем с производительностью? Чтобы исключить подозрения на CSS, я сравнил IE8 и Chrome и обнаружил, что IE8 намного быстрее, чем Chrome, при проверке отзывов Checkbox! IE8 не поддерживает некоторые свойства CSS3, поэтому изящная деградация использует фоновые изображения для реализации пользовательского интерфейса Checkbox. Если рассуждать логически, большинство проблем с производительностью вызвано скриптами, неужели CSS тоже так негативно влияет на производительность?
id(#myid)
class(.myclass)
tag(div)
adjacent sibling(h1 + p)
child(ul > li)
descendent(li a)
universal(*)
attribute(a[rel=”external”])
pseudo-class and pseudo element(a:hover li:first)
▲ Авторитетная сортировка эффективности селектора CSS
При рисовании флажка пользовательский интерфейс LULU использует расширенные свойства CSS3, такие как штрихи, тени, переходы и т. д. Его стили, такие как проверка и отключение, также реализованы с помощью относительно неэффективных селекторов псевдоклассов и смежных селекторов родственных классов. Более 3000 флажков означают более 3000 фильтров селекторов CSS3, поэтому я предполагаю, что это может быть проблема с производительностью, вызванная селекторами.
.ui-checkbox{
…
box-sizing: border-box;
box-shadow: inset 0 1px, inset 1px 0, inset -1px 0, inset 0 -1px;
-webkit-transition: color .2s, background-color .1s;
transition: color .2s, background-color .1s;
…
}
:checked + .ui-checkbox, :checked + .ui-checkbox: hover{
color: $borderFocus;
background-color: $backgroundRed;
}
▲ Код стиля флажка пользовательского интерфейса LULU
Чтобы убедиться, что это проблема рендеринга, вызванная селекторами CSS3, попробуйте изменить селектор класса, чтобы переопределить стиль флажка, код выглядит следующим образом.
.ui-checkbox{
…
background: url(….);
….
}
.ui-checkbox-checked {
background-position: 0 -40px;
}
▲ Оптимизированный код стиля флажка LULU UI
В результате галочка «Выбрать все главы» исчезла, а ответ был практически мгновенным.
Кстати, глядя на данные о производительности, рендеринг занимает всего 1777,7 мс.
3. Фронтальная сегментированная загрузка
На данный момент проблема с производительностью, вызванная установкой флажка в вопросе 2, была решена, но явление зависания все еще существует во время процесса загрузки страницы.Если глав слишком много, полоса прокрутки находится почти в приостановленном состоянии.
Это несложно понять.Чем больше глав на странице, тем больше DOM-узлов нужно отрисовать за один раз.Даже если вы работаете с DOM только один раз и вставляете такое количество узлов за короткий промежуток времени, он все равно будет занять длительное время. Обычной практикой является использование общих стратегий, таких как пейджинг, загрузка из раскрывающегося списка и т. д., для решения этой проблемы.
▲Процесс загрузки страницыКак видно из рисунка выше, в процессе загрузки страницы время Recalculte Style (стиля пересчета) достигло 1,08 с. В чем заключается концепция? Даже для многоузловой веб-страницы, такой как пространство QQ, которая собирает изображения, поля ввода и кнопки управления, время, необходимое для использования стиля пересчета во время процесса загрузки, составляет всего около 293,4 мс.
▲ QQ space Процесс загрузкиКрайне важно загружать контент сегментами.Наша стратегия сегментированной загрузки: данные по-прежнему подтягиваются за один раз, а фронтенд выполняет сегментированный рендеринг и вставляет его в DOM сегментами.
Оптимальным решением, конечно, является модификация внутреннего интерфейса для поддержки внешнего интерфейса для многократного извлечения данных глав, но времени мало, и внутренняя модификация интерфейса также требует некоторого времени, поэтому требуемая сегментация не достигается. Результаты клиентской сегментации показаны в следующей таблице, и время загрузки не сильно отличается.
количество глав | Время загрузки до сегментации | Время загрузки после сегментации |
---|---|---|
3000 | 0.366s | 0.391s |
5000 | 0.712s | 0.699s |
7000 | 0.938s | 0.936s |
▲Результаты сегментированных данных переднего плана
▲ Сегментированные результаты загрузкиПри сравнении вышеприведенных 4 наборов изображений рендеринг и рисование уменьшаются после сегментации, но по мере увеличения количества сегментов разница постепенно сужается. Может случиться так, что вставка данных в DOM в первый раз также сопровождается загрузкой других элементов и ресурсов на странице, поэтому эффект от первой сегментации значителен. Однако по-прежнему есть проблемы со временем рендеринга, близким к 1,5 с.
▲Сравнение до и после загрузки Checkbox в разделахТеоретически сегментация должна быть эффективной, но на практике проверка «Выбрать все главы» после сегментации относительно сокращается с точки зрения рендеринга, написания сценариев и перерисовки, но разница не очевидна. Предположение: его последовательная вставка в DOM слишком непрерывна без промежутков, поэтому для дальнейшей оптимизации используется таймер.
использование таймера
Таймер может задержать выполнение JS на некоторое время, и это событие ставится в очередь в конце очереди событий в текущем потоке. Здесь мы можем использовать метод таймера setTimeout и установить время задержки на 0 мс. Хотя мы установили время на 0 мс, минимальная задержка браузера в среднем составляет 16 мс. Эти 16 мс незаметны для пользователя, но браузер может воспользоваться этой возможностью, чтобы перевести дух.
«Таймер предотвращает зависание браузера, если генерируется большое количество элементов DOM.
— Читы Javascript Ниндзя
Объяснение о 16,66 мс:
«Наша цель — обеспечить частоту обновления страницы выше 60 кадров в секунду (кадров) в секунду, что соответствует частоте обновления большинства мониторов (60 Гц). Если анимация веб-страницы может достигать 60 кадров в секунду (кадров) в секунду, то Он обновляется синхронно с монитором для достижения наилучшего визуального эффекта.Это означает 60 повторных рендеров в секунду, и каждый повторный рендеринг может занимать не более 16,66 миллисекунд».
- Из статьи Хорва
Попробуйте добавить использование таймеров на основе сегментированной загрузки, давайте взглянем на сравнение данных производительности:
▲Продолжительность загрузки главы Mock 7000,Левое изображение не использует таймер, правое изображение использует таймер
Очевидно есть значительное падение Rendering (рендеринга) (около 1300мс), а данные близки к нашему ожидаемому значению (368мс)! Однако на проверку «Выбрать все главы» это не сильно влияет, сравнение данных выглядит следующим образом:
▲ Установите флажок, левое изображение не использует таймер, правое изображение использует таймерВ-четвертых, уменьшите количество операций и доступа к DOM.
До сих пор все 3 проблемы с производительностью дали ожидаемые результаты, но я решил забыть о браузере IE7. В IE7 проверка «Выбрать все главы» по-прежнему имеет задержку ответа. Да, исходная платформа ПК должна поддерживать IE7 и выше.
Прочитав отметку времени печати, я обнаружил, что получение и обновление общего количества, общей стоимости и общего количества слов в выбранных главах занимает слишком много времени. Это связано с тем, что каждый раз, когда Checkbox установлен и снят, содержимое числовых элементов будет получено из DOM в режиме реального времени.В IE7 с низкой производительностью рендеринга узкое место будет более очевидным. Поэтому мы кешируем текущее общее количество глав, общую цену, общее количество слов и элементы, отображающие эти числа в объекте, а не читаемые в реальном времени.Давайте посмотрим на данные:
количество глав | До оптимизации (мс) | После оптимизации (мс) |
---|---|---|
3000 | 864 | 177 |
5000 | 1317 | 169 |
7000 | 1774 | 180 |
▲ Взять среднее значение из 10 тестовых данных.
V. Оптимизация опыта на основе бизнес-характеристик
Вышеупомянутые четыре проблемы опыта были в основном решены здесь Теперь давайте взглянем на почти 7000 глав «Создание мира с помощью фермы»:
▲ Глава 7000 «Перенос фермы в другой мир»Результат оптимизации производительности был идеальным, но теперь все пользователи смогут видеть Загрузка каждый раз, когда они посещают страницу подписки, независимо от того, сколько там глав.Количество глав можно терпеть, но когда количество глав маленький, он все еще вызывает у людей недружелюбное чувство. В конце концов, загрузка данных страницы напрямую — это лучшая практика.
количество глав | Количество (это) | процент |
---|---|---|
более 5000 | 19 | 0.003% |
больше 2000 && меньше 5000 | 260 | 0.045% |
▲ Данные библиотеки
Данные показывают, что книг с количеством глав более 2000 всего несколько, а книг всего больше 200. Потеря опыта загрузки из-за малого количества книг (составляет 0,045%) неудовлетворительна!
Чтобы позволить более чем 99% пользователей быстрее просматривать контент, страницы подписки на большинство наших книг могут напрямую передавать данные! Поэтому я договорился со студентами бэкенда о простом логотипе.Когда количество глав меньше или равно 2000, данные будут выведены напрямую.Когда количество глав больше 2000, AJAX подтянет данные и вставьте его на страницу в разделы. До этого момента мир Штормграда наконец-то мирный ^_^.
▲ Нет опыта загрузкиЧтобы быть лучше для нас, нельзя отказаться от некоторых небольших оптимизаций для сжатия объема данных AJAX, таких как сжатие полей, уменьшение избыточных полей и т. д. Даже при объемах данных более 5000 глав эти оптимизации могут привести к сокращению объема передаваемых данных.
буря утихла
Эта буря производительности на некоторое время утихла, и на этот раз я делюсь ею не только для того, чтобы сделать собственные выводы, но и для того, чтобы помочь детской обуви, которая также сталкивается с узкими местами в производительности. На самом деле, в дополнение к этому, вы можете придумать некоторые возможные решения для дальнейшего улучшения производительности страницы, например: использовать requestIdleCallback, чтобы в полной мере использовать время простоя браузера, чтобы сделать что-то для повышения производительности; использовать алгоритм timechunk для узлов для точного планирования каждую секунду Сколько узлов создается часами, сегментация интерфейса, упомянутая выше, и так далее. Оптимизация производительности бесконечна, и мы найдем возможность применить больше решений для страниц подписки и других страниц, которые необходимо оптимизировать в будущем.
PS: если вы хотите узнать больше о пользовательском интерфейсе LULU, вы можете перейти по этой ссылке: https://l-ui.com/