Comment fonctionne la liaison de données dans le AngularJS
cadre?
Je n'ai pas trouvé de détails techniques sur leur site . Il est plus ou moins clair comment cela fonctionne lorsque les données sont propagées de la vue au modèle. Mais comment AngularJS suit-il les changements des propriétés du modèle sans setters et getters?
J'ai trouvé qu'il existe des observateurs JavaScript qui peuvent faire ce travail. Mais ils ne sont pas pris en charge dans Internet Explorer 6 et Internet Explorer 7 . Alors, comment AngularJS sait-il que j'ai changé par exemple ce qui suit et reflété ce changement sur une vue?
myobject.myproperty="new value";
javascript
angularjs
data-binding
Pashec
la source
la source
Réponses:
AngularJS se souvient de la valeur et la compare à une valeur précédente. Il s'agit d'une vérification de base. S'il y a un changement de valeur, il déclenche l'événement change.
La
$apply()
méthode, qui est ce que vous appelez lorsque vous passez d'un monde non AngularJS à un monde AngularJS, appelle$digest()
. Un condensé est tout simplement une vieille vérification. Il fonctionne sur tous les navigateurs et est totalement prévisible.Pour comparer la vérification incorrecte (AngularJS) et les auditeurs de changement ( KnockoutJS et Backbone.js ): Bien que la vérification incorrecte puisse sembler simple, et même inefficace (j'y reviendrai plus tard), il s'avère qu'elle est toujours sémantiquement correcte, tandis que les écouteurs de changement ont beaucoup de cas étranges et ont besoin de choses comme le suivi des dépendances pour le rendre plus sémantiquement correct. Le suivi des dépendances de KnockoutJS est une fonctionnalité intelligente pour un problème que AngularJS n'a pas.
Problèmes avec les écouteurs de changement:
Et la performance?
Il peut donc sembler que nous sommes lents, car la vérification des résultats est inefficace. C'est là que nous devons examiner les nombres réels plutôt que de simplement avoir des arguments théoriques, mais définissons d'abord certaines contraintes.
Les humains sont:
Lent - Tout ce qui dépasse 50 ms est imperceptible pour l'homme et peut donc être considéré comme "instantané".
Limité - Vous ne pouvez pas vraiment montrer plus de 2000 informations à un humain sur une seule page. Rien de plus que cela est vraiment une mauvaise interface utilisateur, et les humains ne peuvent pas traiter cela de toute façon.
La vraie question est donc la suivante: combien de comparaisons pouvez-vous faire sur un navigateur en 50 ms? C'est une question difficile à répondre car de nombreux facteurs entrent en jeu, mais voici un cas de test: http://jsperf.com/angularjs-digest/6 qui crée 10 000 observateurs. Sur un navigateur moderne, cela prend un peu moins de 6 ms. Sur Internet Explorer 8, cela prend environ 40 ms. Comme vous pouvez le voir, ce n'est pas un problème, même sur les navigateurs lents de nos jours. Il y a une mise en garde: les comparaisons doivent être simples pour s'adapter à la limite de temps ... Malheureusement, il est beaucoup trop facile d'ajouter une comparaison lente dans AngularJS, il est donc facile de créer des applications lentes lorsque vous ne savez pas ce que vous faites. Mais nous espérons avoir une réponse en fournissant un module d'instrumentation, qui vous montrerait quelles sont les comparaisons lentes.
Il s'avère que les jeux vidéo et les GPU utilisent l'approche de vérification des erreurs, notamment parce qu'elle est cohérente. Tant qu'ils dépassent le taux de rafraîchissement du moniteur (généralement 50-60 Hz, ou toutes les 16,6-20 ms), toute performance supérieure à celle-ci est un gaspillage, il est donc préférable de dessiner plus de choses que d'augmenter les FPS.
la source
Misko a déjà donné une excellente description du fonctionnement des liaisons de données, mais je voudrais ajouter mon point de vue sur le problème de performances avec la liaison de données.
Comme l'a déclaré Misko, environ 2000 liaisons sont l'endroit où vous commencez à voir des problèmes, mais vous ne devriez pas avoir plus de 2000 informations sur une page de toute façon. Cela peut être vrai, mais toutes les liaisons de données ne sont pas visibles pour l'utilisateur. Une fois que vous commencez à créer n'importe quel type de widget ou de grille de données avec une liaison bidirectionnelle, vous pouvez facilement atteindre 2000 liaisons, sans avoir une mauvaise UX.
Prenons par exemple une zone de liste déroulante dans laquelle vous pouvez taper du texte pour filtrer les options disponibles. Ce type de contrôle pourrait avoir ~ 150 éléments et être encore très utilisable. S'il a une fonctionnalité supplémentaire (par exemple une classe spécifique sur l'option actuellement sélectionnée), vous commencez à obtenir 3-5 liaisons par option. Mettez trois de ces widgets sur une page (par exemple, l'un pour sélectionner un pays, l'autre pour sélectionner une ville dans ledit pays, et le troisième pour sélectionner un hôtel) et vous vous trouvez déjà entre 1000 et 2000 liaisons.
Ou envisagez une grille de données dans une application Web d'entreprise. 50 lignes par page n'est pas déraisonnable, chacune pouvant avoir 10 à 20 colonnes. Si vous créez cela avec ng-repeats et / ou avez des informations dans certaines cellules qui utilisent des liaisons, vous pourriez approcher 2000 liaisons avec cette seule grille.
Je trouve que c'est un énorme problème lorsque je travaille avec AngularJS, et la seule solution que j'ai pu trouver jusqu'à présent est de construire des widgets sans utiliser de liaison bidirectionnelle, au lieu d'utiliser ngOnce, de désenregistrer des observateurs et des astuces similaires, ou de construire directives qui construisent le DOM avec jQuery et manipulation DOM. Je pense que cela va à l'encontre du but d'utiliser Angular en premier lieu.
Je serais ravi d'entendre des suggestions sur d'autres façons de gérer cela, mais alors je devrais peut-être écrire ma propre question. Je voulais mettre cela dans un commentaire, mais cela s'est avéré beaucoup trop long pour cela ...
TL; DR
La liaison de données peut entraîner des problèmes de performances sur des pages complexes.
la source
En vérifiant mal l'
$scope
objetAngular maintient un simple
array
observateur dans les$scope
objets. Si vous en inspectez,$scope
vous constaterez qu'il contient unarray
appelé$$watchers
.Chaque observateur est un
object
qui contient entre autresattribute
nom ou quelque chose de plus compliqué.$scope
comme 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
$watch
unattribute
on$scope
.Vous pouvez placer une
{{}}
interpolation dans votre modèle (un observateur sera créé pour vous sur le courant$scope
).Vous pouvez demander une directive telle que
ng-model
définir l'observateur pour vous.Le
$digest
cycle vérifie tous les observateurs par rapport à leur dernière valeurLorsque 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
$scope
et de tous ses enfants . Pour chacun$scope
object
, nous itérons sur son$$watchers
array
et é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 unAJAX
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
$scope
est saleSi un observateur est déclenché, l'application sait que quelque chose a changé et
$scope
est marqué comme sale.Les fonctions d'observateur peuvent modifier d'autres attributs sur
$scope
ou sur un parent$scope
. Si une$watcher
fonction a été déclenchée, nous ne pouvons pas garantir que nos autres$scope
sont 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'
$scope
arborescence. Nous pouvons changer une valeur sur une valeur plus élevée$scope
qui a déjà été digérée. Peut-être que nous changeons une valeur sur le$rootScope
.Si le
$digest
est sale, nous exécutons à$digest
nouveau tout le cycleNous parcourons continuellement le
$digest
cycle jusqu'à ce que le cycle de résumé soit net (toutes les$watch
expressions 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:
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
$scope
hié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-repeat
plus d'un grandJSON
array
par 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
$scope
arbre. 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:
ou
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-repeat
avec de nombreux articles.la source
Ceci est ma compréhension de base. C'est peut-être faux!
$watch
méthode.$apply
méthode.$apply
la$digest
méthode est invoquée qui passe par chacune des montres et vérifie si elles ont changé depuis la dernière exécution$digest
.Dans le développement normal, la syntaxe de liaison de données dans le code HTML indique au compilateur AngularJS de créer les montres pour vous et les méthodes de contrôleur sont
$apply
déjà exécutées à l'intérieur . Pour le développeur de l'application, tout est transparent.la source
Je me le demandais moi-même un moment. Sans setters, comment
AngularJS
remarque-t-on les changements$scope
objet? Les interroge-t-il?Ce qu'il fait est le suivant: tout endroit "normal" dans lequel vous modifiez le modèle a déjà été appelé depuis les entrailles de
AngularJS
, donc il$apply
vous appelle automatiquement après l'exécution de votre code. Supposons que votre contrôleur dispose d'une méthode qui est liée àng-click
un élément. Parce que leAngularJS
câblage de l'appel de cette méthode ensemble pour vous, il a une chance de faire un$apply
à l'endroit approprié. De même, pour les expressions qui apparaissent directement dans les vues, celles-ci sont exécutées parAngularJS
ainsi il fait le$apply
.Lorsque la documentation parle de devoir appeler
$apply
manuellement du code en dehors deAngularJS
, elle parle de code qui, une fois exécuté, ne provient pas deAngularJS
lui-même dans la pile des appels.la source
Expliquer avec des images:
La liaison de données a besoin d'un mappage
La référence dans la portée n'est pas exactement la référence dans le modèle. Lorsque vous liez des données à deux objets, vous avez besoin d'un troisième qui écoute le premier et modifie l'autre.
Ici, lorsque vous modifiez le
<input>
, vous touchez le data-ref3 . Et le mécanisme classique de liaison de données changera data-ref4 . Alors, comment l'autre{{data}}
se déplaceront expressions?Les événements mènent à $ digest ()
Angular maintient une
oldValue
etnewValue
de chaque reliure. Et après chaque événement angulaire , la célèbre$digest()
boucle vérifiera la WatchList pour voir si quelque chose a changé. Ces événements angulaires sontng-click
,ng-change
,$http
terminés ... La$digest()
boucle de volonté aussi longtemps que toutoldValue
diffère de lanewValue
.Dans l'image précédente, il remarquera que data-ref1 et data-ref2 ont changé.
Conclusions
C'est un peu comme l'oeuf et le poulet. Vous ne savez jamais qui commence, mais j'espère que cela fonctionne la plupart du temps comme prévu.
L'autre point est que vous pouvez facilement comprendre l'impact profond d'une simple liaison sur la mémoire et le CPU. Espérons que les ordinateurs de bureau soient suffisamment gros pour gérer cela. Les téléphones portables ne sont pas si forts.
la source
Évidemment, il n'y a pas de vérification périodique pour
Scope
savoir s'il y a un changement dans les objets qui y sont attachés. Tous les objets attachés à la portée ne sont pas surveillés. La portée maintient de manière prototypique un $$ observateurs .Scope
seulement itère à travers cela$$watchers
quand$digest
est appelé.Angular ajoute un observateur aux observateurs $$ pour chacun de ces
La fonction $ watch prend trois paramètres:
Il y a une chose intéressante dans Angular appelée Digest Cycle. Le cycle $ digest démarre à la suite d'un appel à $ scope. $ Digest (). Supposons que vous modifiez un modèle $ scope dans une fonction de gestionnaire via la directive ng-click. Dans ce cas, AngularJS déclenche automatiquement un cycle $ digest en appelant $ digest (). En plus de ng-click, il existe plusieurs autres directives / services intégrés qui vous permettent de changer de modèle (par exemple ng-model, $ timeout, etc.) et déclencher automatiquement un cycle $ digest. L'implémentation approximative de $ digest ressemble à ceci.
Si nous utilisons la fonction setTimeout () de JavaScript pour mettre à jour un modèle de portée, Angular n'a aucun moyen de savoir ce que vous pourriez changer. Dans ce cas, il est de notre responsabilité d'appeler $ apply () manuellement, ce qui déclenche un cycle de $ digest. De même, si vous avez une directive qui configure un écouteur d'événement DOM et modifie certains modèles à l'intérieur de la fonction de gestionnaire, vous devez appeler $ apply () pour garantir que les modifications prennent effet. La grande idée de $ apply est que nous pouvons exécuter du code qui ne connaît pas Angular, ce code peut encore changer les choses sur la portée. Si nous encapsulons ce code dans $ apply, il se chargera d'appeler $ digest (). Implémentation approximative de $ apply ().
la source
AngularJS gère le mécanisme de liaison de données à l'aide de trois fonctions puissantes: $ watch () , $ digest () et $ apply () . La plupart du temps, AngularJS appellera $ scope. $ Watch () et $ scope. $ Digest (), mais dans certains cas, vous devrez peut-être appeler ces fonctions manuellement pour mettre à jour avec de nouvelles valeurs.
$ watch () : -
$ digest () -
$ appliquer () -
la source
Il est arrivé que je devais lier un modèle de données d'une personne à un formulaire, ce que j'ai fait était une cartographie directe des données avec le formulaire.
Par exemple, si le modèle avait quelque chose comme:
L'entrée de contrôle du formulaire:
De cette façon, si vous modifiez la valeur du contrôleur d'objet, cela se reflétera automatiquement dans la vue.
Un exemple où j'ai passé le modèle est mis à jour à partir des données du serveur est lorsque vous demandez un code postal et un code postal basés sur des charges écrites une liste des colonies et des villes associées à cette vue, et par défaut définissez la première valeur avec l'utilisateur. Et cela, j'ai très bien fonctionné, ce qui arrive, c'est que cela
angularJS
prend parfois quelques secondes pour rafraîchir le modèle, pour ce faire, vous pouvez mettre un spinner tout en affichant les données.la source
La liaison de données unidirectionnelle est une approche dans laquelle une valeur est extraite du modèle de données et insérée dans un élément HTML. Il n'y a aucun moyen de mettre à jour le modèle à partir de la vue. Il est utilisé dans les systèmes de modèles classiques. Ces systèmes lient les données dans une seule direction.
La liaison de données dans les applications angulaires est la synchronisation automatique des données entre le modèle et les composants de vue.
La liaison de données vous permet de traiter le modèle comme la source de vérité unique dans votre application. La vue est une projection du modèle à tout moment. Si le modèle est modifié, la vue reflète le changement et vice versa.
la source
Voici un exemple de liaison de données avec AngularJS, à l'aide d'un champ de saisie. J'expliquerai plus tard
Code HTML
Code AngularJS
Comme vous pouvez le voir dans l'exemple ci-dessus, AngularJS utilise
ng-model
pour écouter et regarder ce qui se passe sur les éléments HTML, en particulier sur lesinput
champs. Quand quelque chose arrive, faites quelque chose. Dans notre cas,ng-model
est lié à notre vue, en utilisant la notation moustache{{}}
. Tout ce qui est tapé à l'intérieur du champ de saisie s'affiche instantanément à l'écran. Et c'est la beauté de la liaison de données, en utilisant AngularJS dans sa forme la plus simple.J'espère que cela t'aides.
Voir un exemple de travail ici sur Codepen
la source
AngularJs prend en charge la liaison de données bidirectionnelle .
Signifie que vous pouvez accéder aux données Affichage -> Contrôleur et contrôleur -> Affichage
Pour Ex.
1)
O / P
Vous pouvez lier des données dans
ng-model
Like: -2)
Ici, dans l'exemple ci-dessus, quelle que soit l'entrée donnée par l'utilisateur, elle sera visible dans la
<div>
balise.Si vous voulez lier l'entrée de html au contrôleur: -
3)
Ici, si vous souhaitez utiliser l'entrée
name
dans le contrôleur,ng-model
lie notre point de vue et le rendre dans l'expression{{ }}
.ng-model
sont les données qui sont montrées à l'utilisateur dans la vue et avec lesquelles l'utilisateur interagit.Il est donc facile de lier des données dans AngularJs.
la source
Angular.js crée un observateur pour chaque modèle que nous créons en vue. Chaque fois qu'un modèle est modifié, une classe "ng-dirty" est ajoutée au modèle, donc l'observateur observera tous les modèles qui ont la classe "ng-dirty" et mettra à jour leurs valeurs dans le contrôleur et vice versa.
la source
liaison de données:
Qu'est-ce que la liaison de données?
Chaque fois que l'utilisateur modifie les données dans la vue, il se produit une mise à jour de ce changement dans le modèle d'étendue et vice versa.
Comment est-ce possible?
Réponse courte: Avec l'aide du cycle de digestion.
Description: js angulaire définit l'observateur sur le modèle d'oscilloscope, ce qui déclenche la fonction d'écoute s'il y a un changement dans le modèle.
// Code de mise à jour Dom avec une nouvelle valeur
});
Alors, quand et comment la fonction de surveillance est-elle appelée?
La fonction d'observateur est appelée dans le cadre du cycle de digestion.
Le cycle de résumé est appelé déclenché automatiquement dans le cadre de js angulaires intégrés dans des directives / services comme ng-model, ng-bind, $ timeout, ng-click et autres .. qui vous permettent de déclencher le cycle de résumé.
Fonction de cycle de digestion:
c'est à dire
$rootScope.$apply()
Remarque: $ apply () est égal à $ rootScope. $ Digest () cela signifie que la vérification incorrecte commence directement à partir de la racine ou du sommet ou de la portée parent jusqu'à toutes les portées $ enfant dans l'application js angulaire.
Les fonctionnalités ci-dessus fonctionnent également dans les navigateurs IE pour les versions mentionnées simplement en vous assurant que votre application est une application js angulaire, ce qui signifie que vous utilisez le fichier de script de framework angularjs référencé dans la balise de script.
Je vous remercie.
la source