Как работает change detection в Angular и чем отличаются стратегии Default и OnPush?
Change Detection
Change detection — механизм, который определяет, что изменились данные, и обновляет DOM. Angular проверяет привязки шаблонов компонента, сравнивая текущие значения с предыдущими.
Откуда запускается проверка
Раньше за этим следила библиотека Zone.js: она перехватывает асинхронные события (клики, таймеры, XHR/fetch) и после каждого запускает проверку всего дерева компонентов сверху вниз. В новых версиях можно работать без Zone.js (zoneless), опираясь на сигналы и явные уведомления.
Default
Проверяются все компоненты при каждом событии. Просто и надёжно, но на больших деревьях тратит время.
OnPush
Компонент проверяется только если:
- изменилась ссылка на входное свойство
@Input()(сравнение по ссылке, а не по содержимому); - событие произошло внутри самого компонента или его обработчика;
- сработал
asyncpipe или обновился сигнал, прочитанный в шаблоне; - проверка запущена вручную через
ChangeDetectorRef.markForCheck().
@Component({
selector: 'app-user',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `{{ user.name }}`,
})
export class UserComponent {
@Input() user!: User;
}Типичная ошибка OnPush
Мутация объекта не обновит представление:
this.user.name = 'Ivan'; // ссылка прежняя — не обновится
this.user = { ...this.user, name: 'Ivan' }; // новая ссылка — обновитсяПоэтому с OnPush используют неизменяемые данные.
Как управлять вручную
markForCheck()— пометить компонент и предков для проверки.detectChanges()— проверить поддерево немедленно.detach()/reattach()— отключить и вернуть проверку.
Зачем OnPush
Сокращает число проверок и ускоряет приложение; хорошо сочетается с async pipe, сигналами и иммутабельным состоянием.
Коротко для собеседования
Default проверяет все компоненты на каждое событие, OnPush — только при смене ссылки в @Input, событии внутри, async pipe или сигнале. Для OnPush данные делают неизменяемыми или вызывают markForCheck().