В чем разница между markForCheck() и detectChanges()
в чем разница между ChangeDetectorRef.markForCheck()
и ChangeDetectorRef.detectChanges()
?
Я только нашел информацию о том, чтобы разница между NgZone.run()
, но не между этими двумя функциями.
для ответов только со ссылкой на документ, пожалуйста, проиллюстрируйте некоторые практические сценарии, чтобы выбрать один из них.
2 ответа:
из документов :
detectChanges (): void
это означает, что если есть случай, когда какая-либо вещь внутри вашей модели (вашего класса) изменилась, но она не отразила представление, вам может потребоваться уведомить Angular, чтобы обнаружить эти изменения (обнаружить локальные изменения) и обновить представление.
возможные сценарии могут быть:
1-The детектор изменений отсоединяется от вида (см. отключить)
2 - обновление произошло, но оно не было внутри угловой зоны, поэтому Angular не знает об этом.
например, когда сторонняя функция обновила вашу модель, и вы хотите обновить представление после этого.
someFunctionThatIsRunByAThirdPartyCode(){ yourModel.text = "new text"; }
поскольку этот код находится за пределами угловой зоны (вероятно), вам, скорее всего , нужно обязательно обнаружить изменения и обновить представление, таким образом :
myFunction(){ someFunctionThatIsRunByAThirdPartyCode(); // Let's detect the changes that above function made to the model which Angular is not aware of. this.cd.detectChanges(); }
Примечание:
есть и другие способы сделать выше работу, другими словами, есть и другие способы, чтобы принести это изменение внутри углового цикла изменения.
** вы можете обернуть эту стороннюю функцию внутри зоны.беги:
myFunction(){ this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode); }
** вы можете обернуть функцию внутри setTimeout:
myFunction(){ setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0); }
3 - Есть также случаи, когда вы обновить модель после
change detection cycle
закончено, где в тех случаи, когда вы получаете эту страшную ошибку:"выражение изменилось после проверки";
это обычно означает (от языка Angular2):
я увидел изменение в вашей модели, которое было вызвано одним из моих принятых способов ( события , запросы XHR , setTimeout и т. д... ) и затем я запустил свое обнаружение изменений, чтобы обновить ваше представление, и я закончил его, но тогда в вашем коде была другая функция, которая снова обновила модель, и я этого не делаю хочу снова запустить мое обнаружение изменений, потому что больше нет грязной проверки, такой как AngularJS :D, и мы должны использовать односторонний поток данных!
вы обязательно столкнетесь с этой ошибкой: P .
несколько способов исправить это:
1- правильно: убедитесь, что обновление находится внутри цикла обнаружения изменений ( обновления Angular2-это один из способов потока, который происходит один раз, не обновляйте модель после этого и переместите свой код в лучшее место / время ).
2- ленивый способ : запустите detectChanges () после этого обновления , чтобы сделать angular2 счастливым, это определенно не лучший способ , но, как вы спросили, каковы возможные сценарии, это один из них.
таким образом, вы говорите : Я искренне знаю, что вы запустили обнаружение изменений, но я хочу, чтобы вы сделали это снова, потому что мне пришлось обновить что-то на лету после того, как вы закончили проверку.
3 - Поместите код внутри
setTimeout
, потому чтоsetTimeout
исправляется по зоне и будет работатьdetectChanges
после того, как все закончится.
документы
markForCheck() : void
помечает все ChangeDetectionStrategy предков, чтобы быть проверены.
это в основном нужен, когда ChangeDetectionStrategy компонента составляет OnPush.
OnPush сам означает, что только запустить обнаружение изменений, если какой-либо из них произошло :
1-Один из @входов компонента был полностью заменен новым значением, или проще говоря, если ссылка на свойство @Input полностью изменилась .
так что если ChangeDetectionStrategy компонента составляет OnPush и тогда у вас есть:
var obj = { name:'Milad' };
и затем вы обновляете / мутируете его, как:
obj.name = "a new name";
это не обновление obj ссылка, следовательно изменение обнаружение не будет выполняться, поэтому представление не отражает обновление/мутацию.
в этом случае вы должны вручную сказать угловой, чтобы проверить и обновить вид (markForCheck);
так что если вы сделали это:
obj.name = "a new name";
вы должны сделать это:
this.cd.markForCheck();
скорее, ниже вызовет обнаружение изменений для запуска:
obj = { name:"a new name" };
который полностью заменил предыдущий объект на новый
{}
;2-An событие сработало, как щелчок или что-то подобное, или любой из дочерних компонентов выпустил событие.
событий, таких как :
- клик
- Keyup
- событий подписка
- etc.
короче :
использовать
detectChanges()
когда вы обновили модель после запуска angular, это обнаружение изменений, или если обновление не было в angular world at все.использовать
markForCheck()
если вы используете OnPush и обходитеChangeDetectionStrategy
путем изменения некоторых данных или вы обновили модель внутри setTimeout;
самая большая разница между ними заключается в том, что
detectChanges()
фактически запускает обнаружение изменений, в то время какmarkForCheck()
не вызывает обнаружение изменений.detectChanges
этот используется для запуска обнаружения изменений для дерева компонентов, начиная с компонента, который вы запускаете
detectChanges()
далее. Таким образом, обнаружение изменений будет выполняться для текущего компонента и всех его дочерних элементов. Angular содержит ссылки на корневое дерево компонентов вApplicationRef
и когда любой асинхронный операция происходит это вызывает обнаружение изменений на этом корневом компоненте через метод оберткиtick()
:@Injectable() export class ApplicationRef_ extends ApplicationRef { ... tick(): void { if (this._runningTick) { throw new Error('ApplicationRef.tick is called recursively'); } const scope = ApplicationRef_._tickScope(); try { this._runningTick = true; this._views.forEach((view) => view.detectChanges()); <------------------
view
вот представление корневого компонента. Там может быть много корневых компонентов, как я описал в каковы последствия начальной загрузки нескольких компонентов.@milad описал причины, по которым вам потенциально может потребоваться запустить обнаружение изменений вручную.
markForCheck
как я уже сказал, это парень вообще не запускает обнаружение изменений. Он просто идет вверх от текущего компонента к корневому компоненту и обновляет их состояние представления до
ChecksEnabled
. Вот исходный код:export function markParentViewsForCheck(view: ViewData) { let currView: ViewData|null = view; while (currView) { if (currView.def.flags & ViewFlags.OnPush) { currView.state |= ViewState.ChecksEnabled; <----------------- } currView = currView.viewContainerParent || currView.parent; } }
фактическое обнаружение изменений для компонента не запланировано, но когда это произойдет в будущем (либо в рамках текущего или следующего цикла CD) родительские представления компонентов будут проверены, даже если они были отсоединены детекторы изменений. Детекторы изменения можно отсоединить либо с помощью
cd.detach()
или указавOnPush
изменить стратегию обнаружения. Все собственные обработчики событий отмечают все родительские представления компонентов для проверки.этот подход часто используется в
ngDoCheck
крюк жизненного цикла. Вы можете прочитать больше в если вы думаетеngDoCheck
означает, что ваш компонент проверяется-прочитайте эту статью.см. также все, что вам нужно знать об обнаружении изменений в Angular для более подробной информации.