Обнаружение Zoneless изменений в Angular 18
В Angular v18 представлена экспериментальная функция, называемая обнаружением Zoneless изменений. Эта технология устраняет необходимость в Zone.js
, библиотеке, которая ранее с самого начала использовалась для обнаружения изменений в Angular. Устранив Zone.js
, мы увидим улучшения в более быстром первоначальном рендеринге, уменьшении размеров пакетов и упрощении отладки.
В этой статье мы углубимся в обнаружение изменений Angular, новую функцию Zoneless и то, какую пользу эта новая функция принесет разработчикам Angular.
Что такое обнаружение изменений?
Представьте, что мы создаем веб-приложение с помощью Angular. Каждый раз, когда пользователь взаимодействует с кнопками или другими элементами приложения, веб-страница должна отражать эти взаимодействия в реальном времени. Именно здесь вступает в силу обнаружение изменений: механизм гарантирует, что пользовательский интерфейс всегда отражает последние изменения в данных приложения. Когда происходит изменение, функция обнаружения изменений определяет конкретные части нашего приложения Angular, которые необходимо обновить. Это гарантирует, что пользователи смогут видеть самую свежую информацию и взаимодействовать с реактивным приложением.
Как работает обнаружение изменений в Angular?
На диаграмме ниже показано, что приложение Angular структурировано как дерево компонентов, где корневой компонент разветвляется на дочерние компоненты. Каждый компонент действует как строительный блок со своим внутренним детектором изменений. Эти компоненты соединяются, образуя древовидную структуру.
Поскольку каждый компонент имеет детектор изменений, вы также можете рассматривать это дерево компонентов как дерево детекторов изменений, отражающее структуру компонента:
Angular начинает обнаружение изменений в нижней части дерева компонентов. Он проходит вверх по дереву, проверяя каждый компонент на наличие изменений. Если обнаружено изменение, Angular затем оценивает родительские компоненты измененного компонента, чтобы увидеть, влияет ли оно также на них. Это гарантирует, что обновления будут происходить только в необходимых компонентах и их дочерних элементах.
Под капотом Angular используется NgZone, сервис-оболочка Zone.js. NgZone создает специальную зону, которая охватывает все приложение Angular, обеспечивая перехватчики жизненного цикла и обнаруживая изменения приложения. Эта зона позволяет Angular отслеживать все асинхронные операции, запускаемые внутри приложения. Он абстрагирует некоторые сложности базовой функциональности Zone.js, позволяя разработчикам сосредоточиться на логике приложения, а не на низкоуровневых манипуляциях с зонами:
На диаграмме выше показаны основные взаимодействия между NgZone, Zone.js и браузером. Браузер инициирует асинхронные операции, Zone.js отслеживает их завершение, а NgZone, построенный на Zone.js, запускает обнаружение изменений Angular для соответствующего обновления представления.
Исправление обезьяны Zone.js
В Angular Zone.js использует технику, называемую «исправлением обезьяны», для управления собственными асинхронными API браузера, такими как таймеры, запросы XHR и события DOM. Вместо непосредственной замены этих функций Zone.js создает вокруг них оболочки. Эти оболочки перехватывают исходное поведение и внедряют дополнительную логику. Это позволяет Zone.js отслеживать начало и окончание этих асинхронных операций и информировать механизм обнаружения изменений Angular о завершении асинхронной задачи.
Проблемы с подходом Zone.js
Текущий механизм обнаружения изменений, основанный на Zone.js, обнаруживает некоторые проблемы по мере роста приложения, в том числе:
- Трудности при отладке: Хотя Zone.js эффективно управляет асинхронными операциями в Angular, его подход к исправлению обезьян изменяет объекты браузера и может усложнить отладку.
- Проблемы с производительностью. При обнаружении текущих изменений платформа проверяет все дерево компонентов при изменении данных. Такой комплексный подход гарантирует, что обновления отражаются повсюду, но он может стать узким местом в производительности в больших приложениях, поскольку не позволяет точно определить конкретные изменения в дереве компонентов.
- Накладные расходы Zone.js: Zone.js сам по себе добавляет некоторые накладные расходы, и каждая новая интеграция асинхронного API в Zone.js может еще больше увеличить стоимость загрузки и инициализации, потенциально замедляя первоначальный запуск приложения.
Для решения вышеуказанных проблем Zone.js в Angular 18 введена экспериментальная функция «обнаружения Zoneless изменений». Этот подход направлен на обнаружение изменений без использования Zone.js, что потенциально может привести к повышению производительности и упрощению процесса разработки.
Zoneless обнаружение изменений
При обнаружении бесзональных изменений, когда данные или состояние компонента изменяются, сам компонент должен сообщить об этом механизму обнаружения изменений Angular. Это устраняет необходимость использования Zone.js в качестве посредника.
Обнаружение бесзональных изменений в Angular определяет конкретный компонент, сообщивший об изменении. Вместо сканирования всего дерева компонентов Angular может обновлять только затронутый компонент и его прямых потомков, что делает процесс более эффективным.
Ниже приведены преимущества бесзонального обнаружения изменений, которые делают его одной из самых интересных функций Angular 18:
- Упрощенная отладка. Zone.js может усложнить отладку, изменяя поведение собственных API-интерфейсов браузера. Опираясь на более стандартные механизмы браузера, обнаружение Zoneless изменений упрощает выявление источника проблем при отладке, особенно в сценариях, где оба кода приложения взаимодействуют с асинхронными операциями.
- Потенциальный прирост производительности: в бесзональном режиме компоненты уведомляют Angular об изменениях. Это позволяет выполнять более целевые обновления, поскольку повторно отображается только затронутый компонент и его прямые потомки, что сокращает ненужную работу браузера.
- Меньший размер пакета: удаление зависимости от Zone.js уменьшает общий размер нашего пакета приложений Angular. Это приводит к более быстрому времени начальной загрузки для пользователей и меньшему потреблению полосы пропускания.
Поэкспериментируйте с обнаружением Zoneless изменений
Давайте рассмотрим использование функции Zoneless
в новом приложении Angular. Прежде чем мы начнем, убедитесь, что в вашей системе установлены Node.js и npm
.
Еще одним обязательным условием является Angular CLI. Запустите следующую команду, чтобы установить Angular CLI глобально, если у вас его еще нет:
npm install -g @angular/cli
Затем давайте создадим новое приложение Angular с именем Zoneless-App
, используя команду ниже:
ng new zoneless-app --no-standalone
После создания проекта откройте файл app.module.ts
в редакторе кода. Добавьте следующий поставщик в app.module.ts
:
import { NgModule, provideExperimentalZonelessChangeDetection } from '@angular/core';
...
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
provideExperimentalZonelessChangeDetection()
],
...
})
export class AppModule { }
ProvideExperimentalZonelessChangeDetection
— это новая функция, которая включает экспериментальный режим обнаружения бесзональных изменений.
Далее нам нужно удалить ссылку Zone.js в файле Angular.json:
"polyfills": [
"zone.js" // remove this reference
],
Вот и все, бесзональная поддержка Angular готова.
Теперь мы можем протестировать обнаружение изменений с помощью Zoneless, используя ChildCompoent
ниже:
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-count',
template: `
<h3>Count in child component: {{Counter}}</h3>
`
})
export class ChildComponent {
@Input() Counter: any;
constructor() { }
}
ChildComponent
является частью AppComponent
:
import { Component } from "@angular/core";
@Component({
selector: 'app-root',
template:`
<h2>Zoneless Change Detection</h2>
<app-count [Counter]='Counter'></app-count>
<button (click)='CountIncrement()'>Add Count</button>`
})
export class AppComponent{
Counter = 1;
CountIncrement(){
this.Counter = this.Counter + 1;
}
}
При нажатии кнопки в AppComponent значение счетчика в ChildComponent
увеличивается. Как показано на снимке экрана ниже, Angular обнаруживает это изменение и обновляет представление ChildComponent, чтобы отразить новое значение:
Обнаружение событий таймера с помощью Zoneless
При обнаружении изменений на основе Zone.js событие таймера, такое как setInterval/setTimeout
, обнаруживается автоматически. Работает ли это с обнаружением бесзональных изменений? Давайте выясним это на следующем примере AppComponent:
import { Component, OnInit, inject } from "@angular/core";
@Component({
selector: 'app-root',
template:`
<h2>Zoneless: Async Change Detection</h2>
<div>Counter 2: {{ counter2 }}</div>
`
})
export class AppComponent implements OnInit{
counter2 = 0;
ngOnInit() {
setInterval(() => {
this.counter2 += 1;
},1000);
}
}
В приведенном выше коде, когда AppComponent инициируется, свойство counter2
увеличивается внутри функции таймера setInterval. Однако изменение значения counter2
не отражается в представлении.
Механизм обнаружения Zoneless изменений не срабатывает автоматически при изменении значения внутри функции таймера. Чтобы обновления отражались в представлении, мы должны сообщить Angular, что что-то изменилось явно. Один из распространенных подходов — использовать ChangeDetectorRef.markForCheck()
, как показано в приведенном ниже коде:
cdr = inject(ChangeDetectorRef);
setInterval(() => {
this.counter2 += 1;
this.cdr.markForCheck();
},1000);
Здесь мы внедряем сервис ChangeDetectorRef
в компонент и вызываем его метод markForCheck()
внутри функции обратного вызова. Это сообщает Angular, что компонент необходимо переоценить на предмет возможных изменений. Это относится и к асинхронным событиям, таким как вызовы API в Angular.
Помимо метода markForCheck
, есть несколько других способов сообщить Angular о произошедших изменениях:
- Сигналы. Если мы используем пользовательские сигналы в шаблоне компонента, изменение этих сигналов запускает повторный рендеринг для отражения новых данных. Сигналы Angular — это реактивные оболочки данных, которые уведомляют компоненты и шаблоны при изменении их базового значения.
- Прослушиватель событий или прямой ввод: всякий раз, когда пользователь напрямую меняет значение входного свойства или взаимодействует с элементами в шаблоне (например, клики, отправку формы), Angular обнаруживает событие и запускает повторный рендеринг.
Zone.js и Zoneless
Важно отметить, что команда Angular взяла на себя обязательство продолжать поддержку Zone.js, поскольку многие существующие приложения Angular полагаются на него. Zone.js будет продолжать получать исправления критических ошибок и исправления безопасности. Это гарантирует, что существующие приложения, использующие Zone.js, останутся стабильными и безопасными.
На данный момент функция Zoneless все еще находится в стадии эксперимента. Это означает, что в API и поведении могут произойти существенные изменения, и он еще не готов к производству.
Команда Angular также взяла на себя обязательство обеспечить разработчикам плавный путь перехода приложения Zone.js на Zoneless. Они включили поддержку Zoneless в Angular CDK и Angular Material в Angular 18. Более подробную информацию можно найти в официальной документации Zoneless здесь.
Будущее Zoneless в Angular
В настоящее время обнаружение Zoneless изменений в Angular является дополнительной экспериментальной функцией. Однако в дорожной карте Angular использование Zoneless по умолчанию является частью цели улучшения опыта разработчиков Angular. Еще одна цель в дорожной карте Angular — поддержка потокового рендеринга на стороне сервера для Zoneless приложений в будущем выпуске.
Хотя его будущее еще не высечено в камне, Zoneless является многообещающим и соответствует современным тенденциям веб-разработки для повышения производительности и удобства разработчиков. Поскольку Angular продолжает развиваться, обнаружение бесзональных изменений, вероятно, станет более заметным и стандартным вариантом для разработчиков Angular.
Надеюсь, вы найдете этот пост полезным. Соответствующий исходный код можно найти в этом репозитории GitHub.
Испытывайте свои приложения Angular точно так же, как это делает пользователь
Отладка приложений Angular может быть затруднена, особенно когда пользователи сталкиваются с проблемами, которые трудно воспроизвести. Если вы заинтересованы в мониторинге и отслеживании состояния и действий Angular для всех ваших пользователей в рабочей среде, попробуйте LogRocket.
LogRocket похож на видеорегистратор для веб- и мобильных приложений, записывающий буквально все, что происходит на вашем сайте, включая сетевые запросы, ошибки JavaScript и многое другое. Вместо того, чтобы гадать, почему возникают проблемы, вы можете агрегировать данные и сообщать о том, в каком состоянии находилось ваше приложение, когда возникла проблема.
Плагин LogRocket NgRx записывает состояние и действия Angular в консоль LogRocket, предоставляя вам контекст о том, что привело к ошибке и в каком состоянии находилось приложение, когда возникла проблема.
Модернизируйте способы отладки приложений Angular — начните следить бесплатно.