Что касается описания показателей производительности внешнего интерфейса, в отрасли есть свои мнения. Таким образом, это связано с производительностью первого экрана и беглостью страниц. На этот раз мы оптимизируем производительность взаимодействия со страницами. с точки зрения анализа беглости страниц. [Рекомендация по соответствующему учебному пособию: «Учебное пособие по Angular»]
Что такое беглость страниц?
Плавность страницы определяется частотой кадров FPS (Frames Per Second — количество кадров в секунду, передаваемых в секунду). Как правило, частота обновления экрана основных браузеров составляет 60 Гц (обновляется 60 раз в секунду), а оптимальная частота кадров — 60 FPS. Чем выше. частота кадров, тем плавнее страница. 60 Гц означает, что экран дисплея будет обновляться каждые 16,6 мс, а это означает, что рендеринг каждой страницы должен быть завершен в течение 16,6 мс, иначе страница будет терять кадры и зависать.根因在于:浏览器中的JavaScript 执行和页面渲染会相互阻塞
.
В инструментах разработчика Chrome мы можем выполнить Cmd+Shift+P и ввести show fps, чтобы быстро открыть панель fps, как показано на следующем рисунке:
Наблюдая за панелью FPS, мы можем легко отслеживать беглость текущей страницы.
1 Факторы, влияющие на производительность страницы.
Плавность взаимодействия со страницей зависит от плавности ответа страницы, а ответ страницы, по сути, представляет собой процесс повторной визуализации изменений состояния страницы на странице.
Процесс ответа страницы примерно следующий:
Как правило, логика обработки событий Event Handler не отнимает слишком много времени, поэтому факторы, влияющие на производительность Angular, в основном заключаются в异步事件触发
и变更检测
. Как правило, логика обработки событий обработчика событий не отнимает слишком много времени, поэтому факторы, влияющие на производительность Angular, в основном заключаются в асинхронном запуске событий и обнаружении изменений.
Для Angular процесс рендеринга страницы — это процесс обнаружения изменений. Понятно, что обнаружение изменений Angular должно быть завершено в течение 16,6 мс, чтобы избежать потери кадров страницы и задержки.
Производительность ответа страницы можно оптимизировать с помощью следующих трех аспектов.
(1) Для этапа триггерного события запуск асинхронных событий может быть уменьшен , чтобы уменьшить общее количество обнаружений изменений и повторной визуализации
(2) Для этапа логики выполнения обработчика событий время выполнения может быть сокращено за счет оптимизации комплекса; логика кода
(3) для привязки данных обнаружения изменений и фазы обновления DOM количество вычислений обнаружения изменений и данных шаблона может быть уменьшено , чтобы сократить время рендеринга
для (2) обработчика событий, в котором необходимо проанализировать конкретные проблемы; подробно и не будет обсуждаться в основном на (1) (3) ) Оптимизация
2 План оптимизации
2.1 Уменьшение запуска асинхронных событий
Angular В режиме обнаружения изменений по умолчанию асинхронные события будут запускать обнаружение глобальных изменений. Таким образом, снижается количество запуска асинхронных событий. значительно улучшит производительность Angular.
Асинхронные события включают события макрозадач и события микрозадач.
Оптимизация асинхронных событий в основном предназначена для событий прослушивания документов. Например, прослушивайте щелчки, перемещения мыши, перемещения мыши... и другие события в документе.
Сценарий события прослушивания:
Renderer2.listen(document,…)
fromEvent(document,…)
document.addEventListener(…)
Событие прослушивания DOM должно быть удалено, если его запуск не требуется.
Например:
сценарии использования команды окна подсказки [pop]: фильтрация столбцов таблицы, щелчок где-то кроме значка или прокрутка страницы, скрытие всплывающего окна фильтра столбца.
Предыдущий метод заключался в непосредственном отслеживании событий щелчка и событий прокрутки. документа в команде pop. Таким образом: Единственным недостатком является то, что окно подсказки не отображается, но события мониторинга все еще есть, что очень неразумно.
Разумное решение: прослушивайте события щелчка и прокрутки только тогда, когда отображается окно подсказки, и удаляйте события прослушивания, когда оно скрыто.
Для часто запускаемых событий прослушивания DOM вы можете использовать операторы rjx для оптимизации событий. Подробности см. в разделе Операторы Rjx. RxJS Марблс.
2.2 Обнаружение изменений
Что такое обнаружение изменений?
Чтобы понять обнаружение изменений, мы можем искать ответы, исходя из целей обнаружения изменений. Целью обнаружения изменений Angular является синхронизация модели (код TypeScript) и шаблона (HTML). Следовательно, обнаружение изменений можно понимать как: обнаружение изменений модели и одновременное обновление шаблона ( DOM ) .
Каков процесс обнаружения изменений?
Выполняя обнаружение изменений в дереве компонентов в порядке сверху вниз , то есть обнаружение изменений сначала выполняется в родительском компоненте, а затем в дочерних компонентах. Сначала проверьте изменения данных родительского компонента, а затем обновите шаблон родительского компонента. При обновлении шаблона при обнаружении дочернего компонента он обновит значение, привязанное к дочернему компоненту, а затем введет дочерний компонент, чтобы проверить, произошло ли изменение. индекс входного значения @Input изменился, пометьте подкомпонент как грязный, что требует последующего обнаружения изменений. После маркировки подкомпонента продолжайте обновлять шаблон после подкомпонента в родительском компоненте. были обновлены, внесите изменения в обнаружение подкомпонента.
2.2.1 Принцип обнаружения изменений Angular
В стандартном режиме обнаружения изменений по умолчанию принцип асинхронных событий, запускающих обнаружение изменений Angular, заключается в том, что angular вызывает методick() ApplicationRef при обработке асинхронных событий с использованием Zone.js для выполнения из корневого компонента. к подкомпоненту. Обнаружение изменений. В процессе инициализации приложения Angular создается экземпляр зоны (NgZone), а затем вся логика запускается в объекте _inner объекта.
Zone.js реализует следующие классы:
Принцип процесса обнаружения примерно следующий:
пользовательские операции вызывают асинхронные события (например: события DOM, запросы интерфейса...)
=> Класс ZoneTask обрабатывает события. Метод зоны runTask() вызывается в функции ignoreTask(). В методе runTask зона передает атрибут экземпляра _zoneDelegate и вызывает перехват ZoneSpec
=> три перехватчика ZoneSpec (onInvokeTask, onInvoke, onHasTask) передают checkStable. () function Trigger Zone.onMicrotaskEmpty.emit(null) Notification
=> Корневой компонент вызывает методick() после прослушивания onMicrotaskEmpty и вызывает detectChanges()
в методе галочки, чтобы начать обнаружение из корневого компонента
=> ··· refreshView()
вызывает executeTemplate()
, в методе executeTemplate
Вызов templateFn()
для обновления значения, привязанного к шаблону и подкомпоненту (这时候会去检测子组件的
输入引用是否改变,如果有改变,会将子组件标记为
«Грязный» ,也就是该子组件需要变更检测
)
Подробная блок-схема принципа обнаружения изменений:
Упростите процесс:
инициируйте асинхронное событие
=> ZoneTask обрабатывает событие
=> ZoneDelegate вызывает перехватчик ZoneSpec для запуска уведомления onMicrotaskEmpty
=> корневой компонент получает уведомление onMicrotaskEmpty, выполняет check() и начинает обнаруживать и обновлять dom
Как видно из приведенного выше кода,当微任务为空的时候才会触发变更检测
.
Простая блок-схема принципа обнаружения изменений:
Справочный блог по анализу исходного кода Angular Zone.js.
2.2.2 Решение по оптимизации обнаружения изменений
1) Используйте
принцип режима OnPush: сократите время, затрачиваемое на одно обнаружение изменений.
Разница между режимом OnPush и режимом по умолчанию заключается в том, что события прослушивания DOM, события таймера и обещания не инициируют обнаружение изменений. Состояние компонента в режиме по умолчанию всегда — CheckAlways, что означает, что компонент необходимо тестировать в каждом цикле обнаружения.
В режиме OnPush: Следующие ситуации активируют обнаружение изменений
S1 и ссылку @Input компонента, который нужно изменить.
S2 События, привязанные к DOM компонента, включая события, привязанные к DOM его подкомпонентов, такие как щелчок, отправка и наведение курсора мыши. @HostListener()
Примечание.
События DOM, отслеживаемые с помощью renderer2.listen(), не запускают обнаружение изменений.
Собственный метод прослушивания dom.addEventListener() не запускает обнаружение изменений.
Также установлен канал S3 и Observable. в то же время.
S4 Используйте следующие методы, чтобы вручную активировать обнаружение изменений:
ChangeDetectorRef.detectChanges(): Запустите обнаружение изменений для текущего компонента и подкомпонентов, не относящихся к OnPush.
ChangeDetectorRef.markForCheck(): пометить текущее представление и всех его предков как «грязные», и обнаружение будет запущено в следующем цикле обнаружения.
ApplicationRef.tick(): не запускает обнаружение изменений
. 2)
Принцип использования NgZone.runOutsideAngular(): уменьшите количество обнаружений изменений
и напишите глобальный мониторинг событий dom в обратном вызове метода NgZone.runOutsideAngular(). Событие dom будет. не запускать обнаружение изменений. Если текущий компонент не был обновлен, вы можете выполнить ловушку обнаружения изменений ChangeDetectorRef в функции обратного вызова, чтобы вручную запустить обнаружение изменений текущего компонента.
Пример: компонент динамического значка app-icon-react
2.2.3 Способ отладки
1. Вы можете использовать плагин Angular DevTools в консоли браузера для просмотра определенного события DOM и статуса обнаружения angular:
Способ 2. Вы можете напрямую ввести: ng.profiler.timeChangeDetection() в консоли, чтобы просмотреть время обнаружения. Этот метод позволяет просмотреть глобальное время обнаружения. Справочный блог Профилирование Обнаружение изменений Angular
2.3 Оптимизация шаблона (HTML)
2.3.1 Уменьшение рендеринга DOM: ngFor плюс trackBy
Используя атрибут trackBy *ngFor, Angular только изменяет и повторно отображает измененные записи без необходимости перезагрузки всего списка записей.
Например: сценарий сортировки таблицы. Если trackBy добавлен в ngFor, при визуализации таблицы будут перемещены только элементы dom строки. Если trackBy не добавлен, сначала будут удалены существующие элементы dom таблицы, а затем будут добавлены элементы dom строки. Очевидно, что производительность перемещения только dom-элементов будет намного лучше.
2.3.2 Не используйте функции в выражениях шаблона.
Не используйте вызовы функций в выражениях шаблона Angular. Вместо этого вы можете использовать канал или переменную после расчета вручную. Когда функции используются в шаблонах, независимо от того, изменилось значение или нет, функция будет выполняться каждый раз при обнаружении изменения, что повлияет на производительность.
Сценарии использования функций в шаблонах:
2.3.3. Сократите использование ngFor.
Использование ngFor повлияет на производительность при большом объеме данных.
Пример:
Использование ngFor:
Без использования ngFor: производительность улучшилась примерно в 10 раз