Новая эра Angular: беззоновое обнаружение изменений.
Фреймворк Angular всегда был на передовом крае разработки веб-приложений. Недавним новшеством команды Angular на пути к повышению эффективности и оптимизации производительности стала функция с интригующим названием provideZonelessChangeDetection. Ее внедрение предвещает переход к “беззоновому” будущему. Разберемся в технических особенностях этой функции и осознаем последствия ее применения. Основная функциональность
Функция Основная функциональность Функция Класс Ниже — пример такой реализации: Функция Чтобы проиллюстрировать практическое применение новой функциональности, рассмотрим следующий пример с dummy-компонентом: Указанный пример демонстрирует, как можно легко интегрировать новую функциональность в стандартные рабочие процессы Angular. Она представляет собой беззоновую альтернативу без ущерба для отзывчивости и функциональности приложения. Это достижение весьма примечательно. Его внедрение означает, что использование только сигналов для создания беззоновых приложений больше не является необходимостью. При условии, что приложение использует конвейер Однако важно отметить, что в отсутствие автоматического обнаружения изменений при наличии механизма Следует помнить, что функция provideZonelessChangeDetection
— это существенное дополнение к инструментарию Angular. По сути, она настраивает два основных провайдера в среде Angular:export function provideZonelessChangeDetection(): EnvironmentProviders {
return makeEnvironmentProviders([
{
provide: ChangeDetectionScheduler,
useExisting: ChangeDetectionSchedulerImpl
},
{
provide: NgZone,
useClass: NoopNgZone
}
]);
}
ChangeDetectionScheduler
для использования ChangeDetectionSchedulerImpl
, класса, предназначенного для управления циклами обнаружения изменений.NgZone
на NoopNgZone
.ChangeDetectionSchedulerImpl
прост, элегантен и в то же время мощен. Он представляет метод notify
, который настраивает таймер для вызова метода ApplicationRef.tick()
. Этот метод очень важен, поскольку он запускает обнаружение изменений сверху донизу во всем приложении.@Injectable({ providedIn: 'root' })
class ChangeDetectionSchedulerImpl implements ChangeDetectionScheduler {
private appRef = inject(ApplicationRef);
private taskService = inject(PendingTasks);
private pendingRenderTaskId: number|null = null;
notify(): void {
if (this.pendingRenderTaskId !== null) return;
this.pendingRenderTaskId = this.taskService.add();
setTimeout(() => {
try {
if (!this.appRef.destroyed) {
this.appRef.tick();
}
} finally {
// Код не приводится для краткости
}
});
}
}notify
играет ключевую роль во внутренних функциях Angular markViewDirty
и markAncestorsForTraversal
, которые срабатывают в различных сценариях, таких как markForCheck
, события шаблона, setInput
, обновления сигналов и т. д.@Component({
selector: 'app-foo',
standalone: true,
imports: [AsyncPipe],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<p>markForCheck: {{ markForCheck }}</p>
<p>signal: {{ sig() }}</p>
<p>byEvent: {{ byEvent }}</p>
<p>Async pipe: {{ num$ | async }}</p>
<button (click)="byEvent = 3">Click</button>`,
})
export class FooComponent {
markForCheck = 1;
sig = signal(1);
byEvent = 2;
num$ = interval(1500);
private cdr = inject(ChangeDetectorRef);
ngOnInit() {
setInterval(() => {
this.markForCheck += 1;
this.cdr.markForCheck();
}, 1000);
setTimeout(() => {
this.sig.set(2);
}, 500);
}
}async
или метод markForCheck
в сочетании с наблюдаемыми переменными, оно должно продолжать работать как положено.zone.js
, необходимо явно запустить процесс такого обнаружения с помощью одного из предписанных методов. Если этого не сделать, обнаружение изменений не будет выполнено.Важные соображения
provideZonelessChangeDetection
все еще находится на начальной стадии развития. Ее еще предстоит проверить и по необходимости внести в нее некоторые изменения. Разработчики, заинтересованные в экспериментах с этой функцией, могут использовать последние сборки Angular и применять конструкцию { import ɵprovideZonelessChangeDetection as provideZonelessChangeDetection } from '@angular/core'
.