867 Stimmen

AngularJS : Verhinderung des Fehlers $digest already in progress beim Aufruf von $scope.$apply()

Ich finde, dass ich meine Seite zu meinem Bereich manuell mehr und mehr seit dem Aufbau einer Anwendung in Angular aktualisieren müssen.

Die einzige mir bekannte Möglichkeit, dies zu tun, ist der Aufruf $apply() aus dem Geltungsbereich meiner Kontrolleure und Weisungen. Das Problem dabei ist, dass es einen Fehler in der Konsole auslöst, der lautet :

Fehler: $digest bereits in Bearbeitung

Weiß jemand, wie man diesen Fehler vermeidet oder das Gleiche auf eine andere Weise erreicht?

11voto

Sagar M Punkte 1138

Erstens: Reparieren Sie es nicht auf diese Weise

if ( ! $scope.$$phase) { 
  $scope.$apply(); 
}

Es macht keinen Sinn, weil $phase nur ein boolesches Flag für den $digest-Zyklus ist, so dass Ihre $apply() manchmal nicht ausgeführt wird. Und denken Sie daran, es ist eine schlechte Praxis.

Verwenden Sie stattdessen $timeout

    $timeout(function(){ 
  // Any code in here will automatically have an $scope.apply() run afterwards 
$scope.myvar = newValue; 
  // And it just works! 
});

Wenn Sie underscore oder lodash verwenden, können Sie defer() benutzen:

_.defer(function(){ 
  $scope.$apply(); 
});

9voto

bullgare Punkte 1523

Manchmal erhalten Sie trotzdem Fehler, wenn Sie diesen Weg wählen ( https://stackoverflow.com/a/12859093/801426 ).

Versuchen Sie dies:

if(! $rootScope.$root.$$phase) {
...

5voto

eHayik Punkte 2656

Versuchen Sie es mit

$scope.applyAsync(function() {
    // your code
});

anstelle von

if(!$scope.$$phase) {
  //$digest or $apply
}

$applyAsync Planen Sie den Aufruf von $apply zu einem späteren Zeitpunkt. Dies kann verwendet werden, um mehrere Ausdrücke, die im selben Digest ausgewertet werden müssen, in eine Warteschlange zu stellen.

HINWEIS: Innerhalb des $digest führt $applyAsync() nur dann einen Flush durch, wenn der aktuelle Bereich der $rootScope ist. Das heißt, wenn Sie $digest in einem untergeordneten Bereich aufrufen, wird die $applyAsync()-Warteschlange nicht implizit geleert.

Ein Beispiel:

  $scope.$applyAsync(function () {
                if (!authService.authenticated) {
                    return;
                }

                if (vm.file !== null) {
                    loadService.setState(SignWizardStates.SIGN);
                } else {
                    loadService.setState(SignWizardStates.UPLOAD_FILE);
                }
            });

Referenzen:

1. Scope.$applyAsync() vs. Scope.$evalAsync() in AngularJS 1.3

  1. AngularJs-Dokumente

5voto

Luc Punkte 81

Sie sollten je nach Kontext $evalAsync oder $timeout verwenden.

Hier ist ein Link mit einer guten Erklärung:

http://www.bennadel.com/blog/2605-scope-evalasync-vs-timeout-in-angularjs.htm

4voto

nelsonomuto Punkte 63

Ich würde Ihnen raten, ein benutzerdefiniertes Ereignis zu verwenden, anstatt einen Verdauungszyklus auszulösen.

Ich habe festgestellt, dass das Senden von benutzerdefinierten Ereignissen und das Registrieren von Zuhörern für diese Ereignisse eine gute Lösung ist, um eine gewünschte Aktion auszulösen, unabhängig davon, ob Sie sich in einem Digest-Zyklus befinden oder nicht.

Durch die Erstellung eines benutzerdefinierten Ereignisses sind Sie auch effizienter mit Ihrem Code, weil Sie nur Hörer auslösen, die das Ereignis abonniert haben, und NICHT alle an den Bereich gebundenen Watches auslösen, wie Sie es tun würden, wenn Sie scope.$apply aufrufen.

$scope.$on('customEventName', function (optionalCustomEventArguments) {
   //TODO: Respond to event
});

$scope.$broadcast('customEventName', optionalCustomEventArguments);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X