2014-07-09 5 views
5

Ricevo l'idea di base del ciclo infinito del digest e di come accade, ma mi sto imbattendo nel problema. Ecco un violino che dimostra il mio codice e problema:

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

Nella console jsfiddle vedrete il digerire ciclo infinito.

Fondamentalmente devo prendere decisioni sui dati che potrebbero non essere ancora stati caricati, quindi devo aspettare che la promessa risolva usando(). Ho una promessa chiamata utente. Ci sono due posti diversi nel codice dove chiamo quindi() sull'utente.

  1. Subito dopo averlo definito. Devo impostare una variabile scope in base ad essa.
  2. In un altro metodo di applicazione, $ scope.isAdmin()

Per il numero 2, potrebbe essere chiesto perché io non uso $ scope.user direttamente nel metodo $ scope.isAdmin(). Il problema è che è possibile chiamare $ scope.isAdmin() prima che la richiesta asincrona per l'utente ritorni, nel qual caso devo "bloccare" prima di tornare da $ scope.isAdmin().

La mia domanda è, che dire $ scope.isAdmin() sta facendo angolare pensare che una variabile 'guardata' è cambiata e che il ciclo di digest deve essere eseguito di nuovo?

$ scope.isAdmin() in realtà non modifica nulla.

ecco il codice ridotta:

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> 

E il 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(); 
    }); 

risposta

13

Così ho finalmente capito il mio problema e ho pensato di rispondere per altri nel caso in cui qualcun altro possa trovare utili queste informazioni.

Il punto cruciale della correzione riguardava 2 concetti: promesse angolari e orologi angolari. Essendo a conoscenza e applicando i 2 concetti insieme, la soluzione era in realtà piuttosto semplice.

Tutto ciò che si mette in $ scope è 'guardato' incluse le funzioni. Ogni volta che qualcosa guardato cambia $ scope. $ Apply() viene eseguito nuovamente per applicare le modifiche. Se una funzione di scope (ad esempio: $ scope.isAdmin()) modifica il suo valore di ritorno da una "applica" alla successiva, attiva un'altra "applica", finché le cose non si stabilizzano e il valore di ritorno non cambia.

Ma nel mio codice stavo restituendo user.then (...) che restituisce appena una nuova promessa (che ha mantenuto il ciclo di applicazione in corso per sempre poiché il valore di ritorno cambiava continuamente).

Nella mia funzione isAdmin() avevo bisogno di posticipare il suo valore di ritorno fino a quando l'utente non ha effettivamente caricato (qualsiasi altro valore restituito sarebbe privo di significato). Così ho cambiato il codice per verificare se la chiamata asincrona dell'utente si era risolta controllando $ scope.user e in tal caso restituendo un valore isAdmin valido. Se $ scope.user non è stato ancora definito, vorrei solo restituire la promessa che ho già creato.

Ho cambiato $ scope.isAdmin() deve essere:

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

    return user; 
}; 

Ha lo stesso effetto del codice originale senza attivare un ciclo di applicazione infinito. In particolare, se $ scope.user non è stato risolto, restituiamo comunque una promessa come prima, restituendo var all'utente. Si noti tuttavia che var utente è la stessa promessa, non una nuova creata da then(), quindi il ciclo di applicazione si stabilizza.

E solo per completezza qui è il jsfiddle aggiornamento:

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

+1

grazie per la risposta alla tua domanda - questo era il bit veramente rilevante per me, che mi ha fatto capire il mio problema: 'Ma nel mio codice ho era [...] che restituisce appena una nuova promessa (che ha mantenuto il ciclo di applicazione in corso per sempre dal momento che il valore di ritorno continuava a cambiare) ' – keithl8041