Was ist der Unterschied zwischen ChangeDetectorRef.markForCheck()
und ChangeDetectorRef.detectChanges()
?
Ich habe nur Informationen über SO bezüglich des Unterschieds NgZone.run()
zwischen diesen beiden Funktionen gefunden, aber nicht zwischen diesen beiden Funktionen.
Für Antworten mit nur einem Verweis auf das Dokument veranschaulichen Sie bitte einige praktische Szenarien, um eine über die andere zu wählen.
angular
angular2-changedetection
Parlament
quelle
quelle
Antworten:
Aus Dokumenten:
Wenn sich in Ihrem Modell (Ihrer Klasse) etwas geändert hat, das jedoch die Ansicht nicht widerspiegelt, müssen Sie Angular möglicherweise benachrichtigen, um diese Änderungen zu erkennen (lokale Änderungen zu erkennen) und die Ansicht zu aktualisieren.
Mögliche Szenarien könnten sein:
1- Der Änderungsdetektor ist von der Ansicht getrennt (siehe Abnehmen ).
2- Es wurde ein Update durchgeführt, das sich jedoch nicht in der Angular Zone befand. Daher weiß Angular nichts davon.
Zum Beispiel, wenn eine Drittanbieterfunktion Ihr Modell aktualisiert hat und Sie die Ansicht danach aktualisieren möchten.
Da sich dieser Code (wahrscheinlich) außerhalb der Angular-Zone befindet, müssen Sie höchstwahrscheinlich sicherstellen, dass die Änderungen erkannt und die Ansicht aktualisiert werden.
HINWEIS :
Es gibt andere Möglichkeiten, die oben genannte Arbeit zu machen, mit anderen Worten, es gibt andere Möglichkeiten, diese Änderung in den Winkeländerungszyklus zu bringen.
** Sie können diese Drittanbieterfunktion in eine zone.run einbinden:
** Sie können die Funktion in ein setTimeout einschließen:
3- Es gibt auch Fälle, in denen Sie das Modell aktualisieren, nachdem das abgeschlossen
change detection cycle
ist. In diesen Fällen erhalten Sie diesen gefürchteten Fehler:"Ausdruck hat sich geändert, nachdem er überprüft wurde";
Dies bedeutet im Allgemeinen (aus der Sprache Angular2):
Ich habe eine Änderung in Ihrem Modell gesehen, die durch eine meiner akzeptierten Methoden (Ereignisse, XHR-Anforderungen, setTimeout und ...) verursacht wurde, und dann habe ich meine Änderungserkennung ausgeführt, um Ihre Ansicht zu aktualisieren, und ich habe sie beendet, aber dann gab es eine andere Funktion in Ihrem Code, der das Modell erneut aktualisiert hat, und ich möchte meine Änderungserkennung nicht erneut ausführen, da es keine schmutzigen Überprüfungen wie AngularJS mehr gibt: D und wir sollten einen Einweg-Datenfluss verwenden!
Sie werden auf jeden Fall auf diesen Fehler stoßen: P.
Einige Möglichkeiten, dies zu beheben:
1- Richtige Methode : Stellen Sie sicher, dass sich die Aktualisierung innerhalb des Änderungserkennungszyklus befindet (Angular2-Aktualisierungen sind ein einmaliger Ablauf, aktualisieren Sie das Modell danach nicht mehr und verschieben Sie Ihren Code an einen besseren Ort / zu einer besseren Zeit).
2- Fauler Weg : Führen Sie nach diesem Update detectChanges () aus, um angle2 glücklich zu machen. Dies ist definitiv nicht der beste Weg, aber da Sie gefragt haben, welche Szenarien möglich sind, ist dies einer von ihnen.
Auf diese Weise sagen Sie: Ich weiß aufrichtig, dass Sie die Änderungserkennung ausgeführt haben, aber ich möchte, dass Sie dies erneut tun, da ich nach Abschluss der Überprüfung im laufenden Betrieb etwas aktualisieren musste.
3- Fügen Sie den Code in a ein
setTimeout
, da ersetTimeout
nach Zonen gepatcht ist unddetectChanges
nach Abschluss ausgeführt wird.Aus den Dokumenten
Dies wird hauptsächlich benötigt, wenn die ChangeDetectionStrategy Ihrer Komponente OnPush ist .
OnPush selbst bedeutet, dass die Änderungserkennung nur ausgeführt wird, wenn eines der folgenden Ereignisse eingetreten ist:
1- Einer der @ -Eingänge der Komponente wurde vollständig durch einen neuen Wert ersetzt oder einfach ausgedrückt, wenn sich die Referenz der @ Input-Eigenschaft insgesamt geändert hat.
Wenn ChangeDetectionStrategy Ihrer Komponente OnPush ist und Sie haben:
Und dann aktualisieren / mutieren Sie es wie folgt:
Dadurch wird die obj- Referenz nicht aktualisiert , daher wird die Änderungserkennung nicht ausgeführt, daher spiegelt die Ansicht nicht die Aktualisierung / Mutation wider .
In diesem Fall müssen Sie Angular manuell anweisen, die Ansicht zu überprüfen und zu aktualisieren (markForCheck).
Wenn Sie dies getan haben:
Sie müssen dies tun:
Im Folgenden wird vielmehr eine Änderungserkennung ausgeführt:
Was das vorherige Objekt vollständig durch ein neues ersetzte
{}
;2- Ein Ereignis wurde ausgelöst, wie ein Klick oder ähnliches, oder eine der untergeordneten Komponenten hat ein Ereignis ausgelöst.
Veranstaltungen wie:
Also kurz gesagt:
Verwenden
detectChanges()
Sie diese Option, wenn Sie das Modell aktualisiert haben, nachdem Angular die Änderungserkennung ausgeführt hat, oder wenn sich das Update überhaupt nicht in der Winkelwelt befunden hat.Verwenden
markForCheck()
Sie diese Option, wenn Sie OnPush verwenden und das umgehen,ChangeDetectionStrategy
indem Sie einige Daten mutieren, oder wenn Sie das Modell in einem setTimeout aktualisiert haben .quelle
detectChanges
aktualisiert die Ansicht. Siehe diese ausführliche Erklärung .this.cdMode === ChangeDetectorStatus.Checked
, dass Sie markForCheck verwenden würden, wenn die Ansicht nicht aktualisiert wird.detectChanges
. Und es gibt keinecdMode
in Angular4.x.x
. Ich schreibe darüber in meinem Artikel. Ich bin froh, dass es dir gefallen hat. Vergiss nicht, dass du es auf Medium empfehlen kannst oder folge mir :)Der größte Unterschied zwischen beiden besteht darin, dass
detectChanges()
die Änderungserkennung tatsächlichmarkForCheck()
ausgelöst wird , während die Änderungserkennung nicht ausgelöst wird.detectChanges
Diese wird verwendet, um die Änderungserkennung für den Komponentenbaum auszuführen, beginnend mit der Komponente, die Sie auslösen
detectChanges()
. Die Änderungserkennung wird also für die aktuelle Komponente und alle ihre untergeordneten Komponenten ausgeführt. Angular enthält Verweise auf den Stammkomponentenbaum imApplicationRef
und wenn eine asynchrone Operation ausgeführt wird, wird die Änderungserkennung für diese Stammkomponente über eine Wrapper-Methode ausgelösttick()
:view
Hier ist die Stammkomponentenansicht. Es kann viele Stamm Komponenten sein , wie ich in der beschrieben Was die Auswirkungen des Bootstrapping mehrere Komponenten sind .@milad beschrieb die Gründe, warum Sie möglicherweise die Änderungserkennung manuell auslösen müssen.
markForCheck
Wie gesagt, dieser Typ löst überhaupt keine Änderungserkennung aus. Es geht einfach von der aktuellen Komponente zur Stammkomponente nach oben und aktualisiert ihren Ansichtsstatus auf
ChecksEnabled
. Hier ist der Quellcode:Die tatsächliche Änderungserkennung für die Komponente ist nicht geplant, aber wenn dies in Zukunft geschehen wird (entweder als Teil des aktuellen oder des nächsten CD-Zyklus), werden die Ansichten der übergeordneten Komponenten überprüft, selbst wenn sie Änderungsdetektoren getrennt haben. Änderungsdetektoren können entweder mithilfe
cd.detach()
oder unter Angabe einerOnPush
Änderungserkennungsstrategie entfernt werden. Alle nativen Ereignishandler markieren alle übergeordneten Komponentenansichten zur Überprüfung.Dieser Ansatz wird häufig im
ngDoCheck
Lifecycle-Hook verwendet. Weitere Informationen finden Sie unter Wenn Sie der Meinung sind,ngDoCheck
dass Ihre Komponente überprüft wird, lesen Sie diesen Artikel .Weitere Informationen finden Sie unter Alles, was Sie über die Änderungserkennung in Angular wissen müssen .
quelle
markForCheck
. Wenn Sie also keine asynchrone Pipe verwenden, sollten Sie diese wahrscheinlich verwenden. Beachten Sie jedoch, dass die Speicheraktualisierung aufgrund eines asynchronen Ereignisses erfolgen sollte, damit die Änderungserkennung gestartet wird. Das ist meistens immer der Fall. Aber es gibt Ausnahmen blog.angularindepth.com/…async pipe
da wir innerhalb des Abonnements normalerweise ein paar Dinge zu tun habencall setFromValues
do some comparison
.. und wennasync
selbst anruft,markForCheck
was ist das Problem, wenn wir es selbst nennen? Aber normalerweise haben wir 2-3 oder manchmal mehr SelektorenngOnInit
, um unterschiedliche Daten zu erhalten ... und wir rufenmarkForCheck
alle an. Ist das in Ordnung?cd.detectChanges()
führt die Änderungserkennung sofort von der aktuellen Komponente über ihre Nachkommen aus.cd.markForCheck()
führt keine Änderungserkennung durch, markiert jedoch seine Vorfahren als erforderlich, um die Änderungserkennung auszuführen. Wenn die Änderungserkennung das nächste Mal irgendwo ausgeführt wird, wird sie auch für die markierten Komponenten ausgeführt.cd.markForCheck()
. Oft wirken sich Änderungen auf mehrere Komponenten aus, und irgendwo wird die Änderungserkennung aufgerufen. Sie sagen im Wesentlichen: Stellen wir einfach sicher, dass diese Komponente in diesem Fall auch aktualisiert wird. (Die Ansicht wird sofort in jedem Projekt aktualisiert, das ich geschrieben habe, aber nicht in jedem Komponententest).cd.detectChanges()
nicht ist derzeit laufende Änderungserkennung, Verwendungcd.markForCheck()
.detectChanges()
wird in diesem Fall Fehler. Dies bedeutet wahrscheinlich, dass Sie versuchen, den Status einer Vorfahrenkomponente zu bearbeiten, was den Annahmen widerspricht, auf denen die Änderungserkennung von Angular basiert.detectChanges()
.markForCheck()
Möglicherweise wird Ihre Ansicht nicht rechtzeitig aktualisiert. Beim Testen von Einheiten, die sich auf Ihre Ansicht auswirken, müssen Sie möglicherweise manuell anrufen,fixture.detectChanges()
wenn dies in der App selbst nicht erforderlich war.detectChanges()
ändern, können Sie durch die Verwendung eine Leistungssteigerung erzielen, da Sie die Änderungserkennung für die Vorfahren der Komponente nicht unnötig ausführen.quelle