Как работает Change Detection в Angular?
Что такое Change Detection?
Change Detection — это механизм Angular, который следит за изменениями данных и обновляет шаблон (DOM), если нужно.
Когда в приложении что-то изменяется — Angular запускает процесс обнаружения изменений и сравнивает значения в компоненте с тем, что уже отрисовано, чтобы определить, нужно ли перерендерить DOM.
Как это работает?
- Angular запускает проверку с самого корневого компонента.
- Проходит по дереву компонентов вниз.
- Проверяет каждый биндинг (
{{ value }}
,[property]
,(event)
) на изменения. - Если значение изменилось — обновляется DOM.
Что запускает Change Detection?
Angular использует библиотеку zone.js
, чтобы автоматически "захватывать" события, вызывающие изменения:
Источник изменения | Пример |
---|---|
События DOM | click , input , change , и т.д. |
Таймеры | setTimeout , setInterval |
HTTP-запросы | HttpClient |
Promise и async/await | fetch().then(...) , await |
Внутренние изменения | this.value = ... |
Пример: автоматическое обновление DOM
@Component({
selector: 'app-example',
template: `<p>{{ counter }}</p> <button (click)="increment()">+</button>`
})
export class ExampleComponent {
counter = 0;
increment() {
this.counter++;
}
}
Angular автоматически отслеживает изменение counter
после клика по кнопке и обновляет DOM.
Change Detection Strategies
Angular поддерживает две стратегии обнаружения изменений:
Стратегия | Описание |
---|---|
Default | Angular проверяет все компоненты при любом изменении |
OnPush | Angular проверяет компонент только при изменении Input-параметров или событиях |
Использование OnPush
:
@Component({
selector: 'app-optimized',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<p>{{ user.name }}</p>`
})
export class OptimizedComponent {
@Input() user!: { name: string };
}
Это уменьшает количество проверок, повышая производительность, особенно в больших приложениях.
Как Angular сравнивает значения?
Angular использует сравнение по ссылке (shallow reference check):
this.user.name = "John"; // не триггерит OnPush!
this.user = { name: "John" }; // триггерит, потому что новая ссылка
Чтобы обновить компонент со стратегией OnPush
— нужно создать новый объект.
Как оптимизировать Change Detection?
- Используйте
ChangeDetectionStrategy.OnPush
везде, где это возможно. - Избегайте частых мутаций объектов/массивов (используйте иммутабельность).
- Используйте
trackBy
в*ngFor
, чтобы избежать лишних перерендеров. - Работайте с
ChangeDetectorRef
иNgZone
для ручного управления:
constructor(private cdr: ChangeDetectorRef) {}
update() {
this.value = newValue;
this.cdr.detectChanges(); // вручную инициируем проверку
}
Важно:
OnPush
не означает, что компонент никогда не будет обновляться. Он всё ещё реагирует на изменения входных данных и события (click, input).