В чем разница между onPush и Default в рамках стратегий проверки изменений?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между OnPush и Default стратегиями проверки изменений
Stragey проверки изменений (Change Detection Strategy) в Angular контролирует, когда и как компонент должен проверяться на изменения. Есть две основные стратегии: Default и OnPush.
Default стратегия
Default — это стандартная стратегия, которая проверяет компонент и все его потомки при любых изменениях в приложении.
import { Component } from '@angular/core';
@Component({
selector: 'app-user',
template: `<h1>{{ user.name }}</h1>`,
// changeDetection: ChangeDetectionStrategy.Default // По умолчанию
})
export class UserComponent {
user = { name: 'John Doe' };
}
Характеристики Default:
- Проверяется всегда: при любом событии (клик, таймер, HTTP запрос)
- Проверяются все компоненты: целое дерево компонентов
- Простая логика: не нужно думать о том, когда обновлять
- Неэффективно: проверяет даже когда не нужно
- Медленнее: на больших приложениях падает производительность
OnPush стратегия
OnPush — оптимизированная стратегия, которая проверяет компонент только когда:
- Изменились входные свойства (Input)
- Произошло событие внутри компонента
- Явно вызвана ChangeDetectorRef.markForCheck()
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-user',
template: `<h1>{{ user.name }}</h1>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent {
@Input() user: { name: string };
}
Характеристики OnPush:
- Проверяется редко: только при изменении Input свойств
- Проверяется компонент и потомки: другие компоненты не затрагиваются
- Требует дисциплины: нужно правильно передавать данные
- Более эффективно: пропускаются ненужные проверки
- Быстрее: на больших приложениях значительно улучшается производительность
Практический пример
// app.component.ts (Parent)
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<button (click)="increment()">Увеличить счётчик: {{ counter }}</button>
<app-user [user]="user"></app-user>
`
})
export class AppComponent {
counter = 0;
user = { name: 'John' };
increment() {
this.counter++; // Не меняем user
}
}
// user.component.ts (Child) с Default стратегией
@Component({
selector: 'app-user',
template: `<h1>{{ user.name }}</h1>`,
changeDetection: ChangeDetectionStrategy.Default
})
export class UserComponentDefault {
@Input() user: { name: string };
}
// user.component.ts (Child) с OnPush стратегией
@Component({
selector: 'app-user',
template: `<h1>{{ user.name }}</h1>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponentOnPush {
@Input() user: { name: string };
}
Когда кликнем на кнопку "Увеличить счётчик":
- Default: UserComponent будет проверен (хотя user не изменился)
- OnPush: UserComponent не будет проверен (так как user не изменился)
Важно: Immutable подход
OnPush требует неизменяемости (immutability) данных. Это означает, что нужно создавать новые объекты, а не изменять существующие:
// НЕПРАВИЛЬНО с OnPush (не сработает)
this.user.name = 'Jane'; // Ссылка осталась той же
// ПРАВИЛЬНО с OnPush (сработает)
this.user = { ...this.user, name: 'Jane' }; // Новый объект
// или
this.user = Object.assign({}, this.user, { name: 'Jane' });
Почему? Потому что Angular с OnPush проверяет ссылку на объект, а не содержимое. Если ссылка не изменилась, Angular не проверяет компонент.
Ручная проверка с ChangeDetectorRef
Иногда нужно явно попросить Angular проверить компонент:
import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'app-timer',
template: `<p>Время: {{ time }}</p>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TimerComponent implements OnInit {
time: number = 0;
constructor(private cdr: ChangeDetectorRef) {}
ngOnInit() {
setInterval(() => {
this.time++;
// Явно просим Angular проверить компонент
this.cdr.markForCheck();
}, 1000);
}
}
Сравнительная таблица
| Свойство | Default | OnPush |
|---|---|---|
| Когда проверяется | Всегда | Только при изменении Input или события |
| Эффективность | Низкая | Высокая |
| Требует immutability | Нет | Да |
| Сложность | Простая | Сложнее |
| Производительность | Медленнее | Быстрее |
| Подходит для | Простых приложений | Больших приложений |
Рекомендации
Используй Default когда:
- Приложение маленькое
- Нет проблем с производительностью
- Данные меняются часто и непредсказуемо
- Не уверен в своих силах
Используй OnPush когда:
- Приложение большое и сложное
- Есть проблемы с производительностью
- Компонент получает данные через @Input
- Можешь гарантировать immutability
- Нужна максимальная оптимизация
Главная разница
Default проверяет компонент при любом изменении в приложении, что неэффективно.
OnPush проверяет компонент только когда:
- Изменились входные свойства (Input)
- Произошло событие в компоненте
- Явно вызвана проверка
ОнПush требует иммутабельного подхода (создание новых объектов вместо изменения существующих).