Изменение цикла обнаружения в Angular - уточнение?
Относительно ChangeDetectorRef
, Я уже знаю, что -
detectChanges
на самом деле вызывает обнаружение изменений, в то время как с -markForCheck
- Фактическое обнаружение изменений для компонента не запланировано, но когда это произойдет в будущем (как часть текущего или следующего цикла CD)
Смотря на markForCheck
- если это не запланировано, то когда оно будет запущено? Очевидно после обратного вызова Observables, асинхронных обратных вызовов и setTimout и событий.
Документы имеют компонент с OnPush
стратегия
@Component({
selector: 'cmp',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `Number of ticks: {{numberOfTicks}}`
})
class Cmp {
numberOfTicks = 0;
constructor(private ref: ChangeDetectorRef) {
setInterval(() => {
this.numberOfTicks++;
// the following is required, otherwise the view will not be updated
this.ref.markForCheck();
}, 1000);
}
}
Вопрос:
Если он пометит для проверки своих предков, для следующего цикла, так кто же запустил текущий цикл? (Это предыдущий вызов setTimeout?)
Поскольку этот код показывает, что каждая секунда заменяется другой - другими словами, каждую секунду обнаруживается изменение (?!).
Что на самом деле здесь происходит через POV шагов?
1 ответ
markForCheck
Как вы уже догадались, и, как следует из названия, скажет Angular пометить компонент как обнаруживаемый для изменения в следующем цикле.
Когда вы пишете setInterval, это то, что вы на самом деле пишете:
constructor(private ref: ChangeDetectorRef) {
setInterval(() => {
this.numberOfTicks++;
// the following is required, otherwise the view will not be updated
this.ref.markForCheck();
detectChangesFromZoneJS(); // this is a psudo code, but you can imagine something like this will happen, which is patched by NGZone
// Note that this is the last function that will always be called by Zone at the end of all the async events
}, 1000);
}
Это обрабатывается ZoneJS.
Обезьяна Zone исправляет все асинхронные события, и когда они заканчиваются, Zone уведомляет Angular, а затем Angular. знает, что пришло время обнаружить изменения (обновить представление на основе последних изменений модели), но когда вы компонент OnPush
не будет обнаруживать изменения, если внутри компонента не произошло особых событий (например, событие щелчка или любой из @input
это изменилось).
Итак, когда вы сознательно говорите markForCheck
Вы в основном говорите: "Я знаю, что вы не должны обнаруживать изменения, потому что это только OnPush, но я говорю вам, чтобы обнаружить это в любом случае"
Итак, шаг за шагом:
Компонент инициализирован, Angular обнаружит все изменения, ваш взгляд обновится
Вы запускаете setInterval, внутри него вы изменяете свою модель, Angular знает, что она не должна обновлять представление, потому что это OnPush
вызывается обратный вызов первого интервала, мы находимся внутри первой функции, вы отмечаете компонент, который должен быть намеренно проверен, мы находимся в конце функции интервала (все еще первый интервал).
Зона уведомляет Anguar о том, что событие Async только что завершено, время для обнаружения изменений
Angular смотрит на OnPush и хочет игнорировать его, но помнит, что вы пометили компонент, который будет проверен принудительно
представление обновляется
мы идем на второй интервал и так далее.