En vérifiant mal l' $scopeobjet
Angular maintient un simple arrayobservateur dans les $scopeobjets. Si vous en inspectez, $scopevous constaterez qu'il contient un arrayappelé $$watchers.
Chaque observateur est un objectqui contient entre autres
- Une expression que l'observateur surveille. Ce pourrait être simplement un
attributenom ou quelque chose de plus compliqué.
- Une dernière valeur connue de l'expression. Cela peut être vérifié par rapport à la valeur calculée actuelle de l'expression. Si les valeurs diffèrent, l'observateur déclenche la fonction et marque le
$scopecomme sale.
- Une fonction qui sera exécutée si l'observateur est sale.
Comment les observateurs sont définis
Il existe de nombreuses façons différentes de définir un observateur dans AngularJS.
Vous pouvez explicitement $watchun attributeon $scope.
$scope.$watch('person.username', validateUnique);
Vous pouvez placer une {{}}interpolation dans votre modèle (un observateur sera créé pour vous sur le courant $scope).
<p>username: {{person.username}}</p>
Vous pouvez demander une directive telle que ng-modeldéfinir l'observateur pour vous.
<input ng-model="person.username" />
Le $digestcycle vérifie tous les observateurs par rapport à leur dernière valeur
Lorsque nous interagissons avec AngularJS via les canaux normaux (ng-model, ng-repeat, etc.), un cycle de résumé sera déclenché par la directive.
Un cycle de digestion est une traversée en profondeur d'abord $scopeet de tous ses enfants . Pour chacun $scope object, nous itérons sur son $$watchers arrayet évaluons toutes les expressions. Si la nouvelle valeur d'expression est différente de la dernière valeur connue, la fonction de l'observateur est appelée. Cette fonction peut recompiler une partie du DOM, recalculer une valeur $scope, déclencher un AJAX request, tout ce que vous avez besoin de faire.
Chaque étendue est traversée et chaque expression de surveillance évaluée et vérifiée par rapport à la dernière valeur.
Si un observateur est déclenché, il $scopeest sale
Si un observateur est déclenché, l'application sait que quelque chose a changé et $scopeest marqué comme sale.
Les fonctions d'observateur peuvent modifier d'autres attributs sur $scopeou sur un parent $scope. Si une $watcherfonction a été déclenchée, nous ne pouvons pas garantir que nos autres $scopesont toujours propres, et nous exécutons donc à nouveau tout le cycle de résumé.
En effet, AngularJS a une liaison bidirectionnelle, de sorte que les données peuvent être transmises dans l' $scopearborescence. Nous pouvons changer une valeur sur une valeur plus élevée $scopequi a déjà été digérée. Peut-être que nous changeons une valeur sur le $rootScope.
Si le $digestest sale, nous exécutons à $digestnouveau tout le cycle
Nous parcourons continuellement le $digestcycle jusqu'à ce que le cycle de résumé soit net (toutes les $watchexpressions ont la même valeur que dans le cycle précédent) ou que nous atteignions la limite de résumé. Par défaut, cette limite est fixée à 10.
Si nous atteignons la limite de résumé, AngularJS déclenchera une erreur dans la console:
10 $digest() iterations reached. Aborting!
Le résumé est dur pour la machine mais facile pour le développeur
Comme vous pouvez le voir, chaque fois que quelque chose change dans une application AngularJS, AngularJS vérifie chaque observateur de la $scopehiérarchie pour voir comment répondre. Pour un développeur, il s'agit d'une énorme amélioration de la productivité, car vous devez maintenant écrire presque aucun code de câblage, AngularJS remarquera simplement si une valeur a changé et rendra le reste de l'application cohérent avec le changement.
Du point de vue de la machine, cela est extrêmement inefficace et ralentira notre application si nous créons trop d'observateurs. Misko a cité un chiffre d'environ 4000 observateurs avant que votre application ne se sente lente sur les navigateurs plus anciens.
Cette limite est facile à atteindre si vous avez ng-repeatplus d'un grand JSON arraypar exemple. Vous pouvez éviter cela en utilisant des fonctionnalités telles que la liaison unique pour compiler un modèle sans créer d'observateurs.
Comment éviter de créer trop d'observateurs
Chaque fois que votre utilisateur interagit avec votre application, chaque observateur de votre application sera évalué au moins une fois. Une grande partie de l'optimisation d'une application AngularJS consiste à réduire le nombre d'observateurs dans votre $scopearbre. Une façon simple de le faire est d'utiliser une liaison unique .
Si vous avez des données qui changeront rarement, vous ne pouvez les lier qu'une seule fois en utilisant la syntaxe ::, comme ceci:
<p>{{::person.username}}</p>
ou
<p ng-bind="::person.username"></p>
La liaison ne sera déclenchée que lorsque le modèle conteneur sera rendu et les données chargées dans $scope.
Ceci est particulièrement important lorsque vous en avez un ng-repeatavec de nombreux articles.
<div ng-repeat="person in people track by username">
{{::person.username}}
</div>