2014-07-09 19 views
5

Ich bekomme die Grundidee der unendlichen Digest-Schleife und wie es passiert, aber ich bin auf das Problem. Hier ist eine Geige meinen Code und Problem demonstriert:

http://jsfiddle.net/eS5e5/1/

In der jsfiddle Konsole Sie die Endlosschleife verdauen sehen werden.

Grundsätzlich muss ich Entscheidungen über Daten treffen, die noch nicht geladen haben, also muss ich warten, bis das Versprechen mit then() aufgelöst wird. Ich habe ein Versprechen namens Benutzer. Es gibt zwei verschiedene Stellen im Code, an denen ich dann() an Benutzer rufe.

  1. Kurz nachdem ich es definiert habe. Ich muss eine Bereichsvariable basierend darauf festlegen. einfach nicht $ scope.user verwenden, um direkt in dem $ scope.isAdmin() -Methode
  2. In einer anderen Rahmen Methode $ scope.isAdmin()

Für die Nummer 2, könnte man sich fragen, warum ich. Das Problem ist, dass $ scope.isAdmin() aufgerufen werden kann, bevor die async-Anfrage für den Benutzer zurückkommt. In diesem Fall muss ich "blocken", bevor ich von $ scope.isAdmin() zurückkomme.

Meine Frage ist, was ist mit $ scope.isAdmin() macht Winkel denken, dass eine "beobachtete" Variable hat sich geändert und dass der Digest-Zyklus erneut ausgeführt werden muss?

$ scope.isAdmin() ändert nichts. Hier

ist die abgespeckte Code:

HTML:

<body ng-controller='myController'> 
    <div ng-if='isAdmin()'>Hi! <strong>{{ user.username }}</strong> is an Admin!!!</div> 
    <div ng-if='!isAdmin()'>Hi! <strong>{{ user.username }}</strong> is NOT an Admin!!!</div> 
</body> 

Und die JS:

angular.module('myApp', []) 
    .factory('myService', function($q, $timeout) { 
    return {   
     getUser: function() { 
     var deferred = $q.defer(); 

     $timeout(function() { 
      deferred.resolve({ username: 'me', isAdmin: true }); 
     }, 2000); 

     return deferred.promise; 
     } 
    }; 
    }) 
    .controller('myController', function($scope, $q, myService) {  
    var getUserDeferred = $q.defer(); 
    var user = getUserDeferred.promise; 
    user.then(function(user) { 
     $scope.user = user; 
     return user; 
    }); 

    $scope.getUser = function() { 
     return myService.getUser().then(function(user) { 
     getUserDeferred.resolve(user); 
     }); 
    }; 

    $scope.isAdmin = function() { 
     return user.then(function(user) { 
     return user.isAdmin; 
     }); 
    }; 

    $scope.getUser(); 
    }); 

Antwort

13

So endlich dachte ich, mein eigenes Problem und dachte, dass ich antworten würde es für andere, falls jemand anderes diese Informationen nützlich finden könnte.

Die Crux des Fixes hatte mit 2 Konzepten zu tun: Winkelversprechen und Winkeluhren. Durch die Kenntnis und Anwendung der beiden Konzepte war die Lösung eigentlich ziemlich einfach.

Alles, was Sie auf $ Scope setzen, wird "überwacht" einschließlich Funktionen. Jedes Mal, wenn etwas beobachtet wird, ändert sich $ scope. $ Apply() wird erneut ausgeführt, um die Änderungen zu übernehmen. Wenn eine Scope-Funktion (zB: $ scope.isAdmin()) ihren Rückgabewert von "apply" auf "apply" ändert, wird ein weiterer "apply" ausgelöst, bis sich die Dinge stabilisieren und der Rückgabewert sich nicht ändert.

Aber in meinem Code gab ich user.then (...) zurück, was nur ein neues Versprechen zurückgibt (was den Anwendungszyklus für immer andauerte, da sich der Rückgabewert ständig änderte).

In meiner isAdmin() - Funktion musste ich den Rückgabewert verzögern, bis der Benutzer tatsächlich geladen wurde (jeder andere Rückgabewert wäre bedeutungslos). Also änderte ich den Code, um zu überprüfen, ob der Async-Aufruf des Benutzers aufgelöst wurde, indem $ scope.user überprüft wurde, und wenn ja, gab er einen gültigen isAdmin-Wert zurück. Wenn $ scope.user immer noch nicht definiert wäre, würde ich nur das Versprechen zurückgeben, das ich bereits erstellt habe.

Ich habe den $ Scope geändert.isAdmin() zu sein:

$scope.isAdmin = function() { 
    if ($scope.user) { 
    return $scope.user.isAdmin; 
    } 

    return user; 
}; 

Dies hat die gleiche Wirkung wie der ursprüngliche Code, ohne einen unendlichen Anwendungszyklus auszulösen. Insbesondere, wenn der $ scope.user nicht aufgelöst wurde, geben wir immer noch ein Versprechen zurück, indem wir den Benutzer var zurückgeben. Beachten Sie jedoch, dass die Benutzervariable das gleiche Versprechen ist, nicht eine neue, die bis dahin erstellt wurde(), so dass sich der Anwendungszyklus stabilisiert.

Und hier nur der Vollständigkeit halber ist die aktualisierte jsfiddle:

http://jsfiddle.net/eS5e5/2/

+1

Vielen Dank für Ihre eigene Frage zu beantworten - dies die wirklich relevant Bit für mich war, was mich mein Problem verstehen: 'Aber in meinem Code, den ich war [...], die gerade ein neues Versprechen zurückgibt (das den Anwendungszyklus für immer fortsetzte, da sich der Rückgabewert ständig änderte) – keithl8041

Verwandte Themen