Una cosa importante da tenere a mente quando si ha a che fare con strumenti di terze parti e con eventi DOM esterni in AngularJS è utilizzare l'operazione del metodo $scope.$apply()
per avviare le modifiche. Funziona in modo sorprendente, ma a volte lo scope stesso è già digerito attraverso un digest (che è fondamentalmente ciò che si innesca il metodo $ apply) e chiamando $ apply quando questo sta succedendo genererà un errore. Quindi, per ovviare a questo, dovrai prestare attenzione al flag $scope.$$phase
che è impostato sull'oscilloscopio ogni volta che si verifica un digest.
Così ora, diciamo che si desidera modificare l'URL e fare fuoco fuori:
$scope.$apply(function() {
$location.path('/home');
});
E questo funziona come previsto, ma ora lascia supporre che il $ ambito è occupato a fare è cosa. Così, invece di controllare per la variabile fase di $$ e supporre che le modifiche saranno raccolti:
if($scope.$$phase) {
$location.path('/home');
}
else {
$scope.$apply(function() {
$location.path('/home');
});
}
Questo è quello che ho fatto (non con la duplicazione del codice ovviamente) e sembra funzionare al 100% del tempo. Quello che mi preoccupa è che in che modo AngularJS preleva la modifica quando l'oscilloscopio è a metà della sua digestione?
Forse questo esempio non è abbastanza specifico. Supponiamo invece qualcosa di più grande. Immagina di avere un'enorme pagina web con un sacco di associazioni e supponiamo che la digestione mastichi linearmente la pagina (presumo che faccia qualcosa di simile rispetto alla priorità ... In questo caso, qualsiasi cosa si presenti nel Primo albero DOM) e aggiornare i collegamenti sulla pagina dall'alto al basso.
<div class="binding">{{ binding1 }}</div>
<div class="binding">{{ binding2 }}</div>
<div class="binding">{{ binding3 }}</div>
<div class="binding">{{ binding4 }}</div>
<div class="binding">{{ binding5 }}</div>
<div class="binding">{{ binding6 }}</div>
<div class="binding">{{ binding7 }}</div>
<div class="binding">{{ binding8 }}</div>
Supponiamo che sia in corso una digestione ed è vicino al centro della coda di digestione. Ora proviamo a provare e modificare un valore vincolante nella parte superiore della pagina da qualche parte.
if($scope.$$phase) {
$scope.binding1 = 'henry';
}
Ora, in qualche modo, AngularJS preleva la modifica e aggiorna correttamente l'associazione. Anche se è possibile considerare che il cambiamento stesso avvenga in precedenza nella coda rispetto a HTML/DOM.
La mia domanda è: come fa AngularJS a gestire questa potenziale condizione di competizione? In qualche modo mi sento a mio agio se gli aggiornamenti 8 sono corretti (), ma poiché lo binding1 si aggiorna (subito senza bisogno di richiamare $ apply di nuovo), questo mi rende un po 'perso. Questo significa che un'altra digestione è stata inviata da qualche parte nel mezzo? O l'oggetto $ scope è più magico di quanto mi aspetti? Suppongo che questo problema sia stato fatto prima, ma dal momento che scoprire la fase $$ e $ scope in primo luogo è stato un po 'complicato, suppongo che anche questo potrebbe essere qualcosa che è caduto attraverso le fessure.
Qualche idea?
Non capisco perché stai cambiando url usando $ scope.apply()? $ location è un servizio angolare quindi prende parte al ciclo di vita, come posso vedere nel codice (https://github.com/angular/angular.js/blob/master/src/ng/location.js) chiama $ rootScope. $ digest() stesso quando cambia l'URL. – matys84pl
Riguardo le associazioni e le condizioni di gara. $ digest ricollegherà tutti gli osservatori finché non ci saranno cambiamenti. Come è possibile osservare aggiungendo i registri ai metodi watcher/binded, chiamerà ogni binding/watcher almeno due volte per essere sicuro che non ci siano cambiamenti e tutti i valori bindati siano stabili. Questi sono solo controlli sporchi che vengono eseguiti fino alla risoluzione di ogni valore (che non è stato modificato in 2 iterazioni del ciclo). Spero possa aiutare. – matys84pl