En raison des besoins réels de développement au travail, j'ai commencé à entrer en contact avec le framework angulaire. De la comparaison initiale, torturée et dévastée par divers problèmes et concepts, j'ai maintenant une certaine compréhension et ressens le besoin de résumer brièvement ma compréhension. Veuillez me pardonner toute lacune.
1. Liaison de données bidirectionnelle
Divers frameworks MV** sont actuellement populaires dans l'industrie, et des frameworks associés émergent constamment, et angulaire en fait partie (MVVM). En fait, le problème principal du framework MV** est de séparer la couche de vue du modèle, de réduire le couplage du code et de parvenir à la séparation des données et des performances. MVC, MVP et MVVM ont tous les mêmes objectifs. mais les différences entre eux résident dans la manière d'associer la couche de modèle à la vue.
La façon dont les données circulent dans les couches de modèle et de vue est devenue la clé du problème. Angular implémente la liaison bidirectionnelle des données via un contrôle de vérification. Ce que l'on appelle la liaison bidirectionnelle signifie que les modifications apportées à la vue peuvent être reflétées dans la couche modèle et que les modifications apportées aux données du modèle peuvent être reflétées dans la vue. Alors, comment Angular réalise-t-il une liaison bidirectionnelle ? Pourquoi devient-il un contrôle sale ? Commençons par une question originale en amont :
html:
<input type="button" value="increase 1" id="J-increase" /> <span id="J-count"></span>
js :
<script> var bindDate = { count: 1, appy: function () { document.querySelector('#J-count').innerHTML = this.count; }, increase: function () { var _this = this; document.querySelector('#J-increase').addEventListener('click', function () { _this.count++; appy(); }, true); }, initialize: function () { // 初始化 this.appy(); // this.increase(); } }; bindDate.initialize(); </script>
Dans l'exemple ci-dessus, il y a deux processus :
La couche de vue affecte la couche de modèle : Cliquer sur le bouton de la page entraîne une augmentation de 1 du nombre de données
Le calque de modèle reflète le calque de vue : Une fois le nombre modifié, il est reflété sur le calque de vue via la fonction d'application
Il s'agit d'un traitement de données qui était auparavant implémenté à l'aide de bibliothèques telles que jquery et YUI. Les problèmes ici sont évidents :
Jetons un coup d'œil à la manière dont Angular traite les données :
La première étape. Ajoutez un observateur : lorsque les données changent, les objets qui doivent être détectés doivent d'abord être enregistrés
// 对angular里面的源码进行了精简 $watch: function(watchExp, listener, objectEquality) { var scope = this, array = scope.$$watchers, watcher = { fn: listener, last: initWatchVal, get: get, exp: watchExp, eq: !!objectEquality }; if (!array) { array = scope.$$watchers = []; } array.unshift(watcher); }
La deuxième étape. Dirt-check : lorsque les données dans une certaine portée changent, vous devez parcourir et détecter les $$watchers = [...]
$digest: function() { while (length--) { watch = watchers[length]; watch.fn(value, lastValue, scope); } }
Cela permet d'obtenir une liaison bidirectionnelle des données. L'implémentation ci-dessus est-elle similaire à un événement personnalisé ? Vous pouvez voir que le modèle de conception observateur ou (éditeur-abonné) est utilisé.
2. Injection de dépendances
Les étudiants qui ont utilisé le framework spring savent que Ioc et AOP sont les deux concepts les plus importants au printemps, et Ioc peut être utilisé pour injecter des dépendances (DI). Il est évident qu'angular a une couleur back-end très forte.
De même, voyons d’abord comment résoudre l’interdépendance des objets sans utiliser DI :
function Car() { ... } Car.prototype = { run: function () {...} } function Benz() { var cat = new Car(); } Benz.prototype = { ... }
Dans l'exemple ci-dessus, la classe Benz dépend de la classe Car, et cette dépendance est résolue directement via le New interne. Les inconvénients sont très évidents. Le couplage de code devient plus élevé, ce qui n'est pas propice à la maintenance. Le framework back-end est conscient de ce problème depuis longtemps. Au début, Spring enregistrait les dépendances entre les objets dans des fichiers XML. Plus tard, il a résolu le problème DI plus facilement grâce à l'annotation. un aperçu du code back-end.
Le langage js lui-même n'a pas de mécanisme d'annotation, alors comment angulaire l'implémente-t-il ?
1.Annotations de simulation
// 注解的模拟 function annotate(fn, strictDi, name) { var $inject; if (!($inject = fn.$inject)) { $inject = []; $inject.push(name); }else if (isArray(fn)) { $inject = fn.slice(0, last); } return $inject; } createInjector.$$annotate = annotate;
2. Création d'un objet d'injection
function createInjector(modulesToLoad, strictDi) { //通过singleton模式创建对象 var providerCache = { $provide: { provider: supportObject(provider), factory: supportObject(factory), service: supportObject(service), value: supportObject(value), constant: supportObject(constant), decorator: decorator } }, instanceCache = {}, instanceInjector = (instanceCache.$injector = createInternalInjector(instanceCache, function(serviceName, caller) { var provider = providerInjector.get(serviceName + providerSuffix, caller); return instanceInjector.invoke(provider.$get, provider, undefined, serviceName); })); return instanceInjector; }
3. Récupérez l'objet d'injection
function invoke(fn, self, locals, serviceName) { var args = [], $inject = annotate(fn, strictDi, serviceName); for (...) { key = $inject[i]; // 替换成依赖的对象 args.push( locals && locals.hasOwnProperty(key) ? locals[key] : getService(key, serviceName) ); } if (isArray(fn)) { fn = fn[length]; } return fn.apply(self, args); }
À ce stade, avez-vous vu beaucoup d'idées de conception de framework back-end ? Il suffit d'en simuler une sans annotation. Pas étonnant que PPK dise qu'angular est "un framework front-end créé par des non-front-enders pour des non-front-ends. fin"
3.communication du contrôleur
Dans le développement réel, le système d'application sera très volumineux. Il est impossible qu'une application n'ait qu'un seul contrôleur, il existe donc une possibilité de communication entre différents contrôleurs. Il existe deux manières principales de résoudre ce problème courant :
1. Mécanisme d'événement : Enregistrer les événements sur $rootScope Le problème est que trop d'événements seront enregistrés sur $rootScope, ce qui entraînera une série de problèmes ultérieurs.
//controller1 app.controller('controller1', function ($rootScope) { $rootScope.$on('eventType', function (arg) { ...... }) }) // controller2 app.controller('controller2', function ($rootScope) { $rootScope.$emit('eventType',arg); or $rootScope.$broadcast('eventType',arg); })
2. Profitez pleinement des fonctionnalités DI du service angulaire via : et utilisez la fonctionnalité selon laquelle le service est un singleton pour agir comme un pont entre les différents contrôleurs
// 注册service app.service('Message', function () { return { count: void(0); } }) // controller1,修改service的count值 app.controller('controller1', function ($scope, Message) { $scope.count = 1; Message.count = $scope.count; }); // controller2, 获取service的count值 app.controller('controller2', function ($scope, Message) { $scope.num = Message.count; });
4.Ciri perkhidmatan
1. Singleton: Hanya perkhidmatan dalam sudut boleh melakukan DI seperti pengawal dan arahan tidak mempunyai fungsi ini secara literal tidak berkaitan dengan perniagaan tertentu, manakala pengawal dan arahan berkait rapat dengan perniagaan tertentu, jadi keunikan perkhidmatan perlu dipastikan.
2. lazy new: angular akan mula-mula menjana penyedia perkhidmatan, tetapi tidak serta-merta menjana perkhidmatan yang sepadan Ia hanya akan membuat seketika perkhidmatan ini apabila ia diperlukan. .
3. Pembekal) klasifikasi: pembekal(), kilang, perkhidmatan, nilai, pemalar, di mana penyedia adalah pelaksanaan paling rendah, dan kaedah lain berdasarkannya Gula sintaksis ( gula), perlu diperhatikan bahawa perkhidmatan ini akhirnya akan menambah kaedah $get, kerana perkhidmatan khusus dihasilkan dengan melaksanakan kaedah $get.
5. Pelaksanaan arahan
Penyusunan arahan merangkumi dua peringkat: menyusun dan memaut. Secara ringkasnya, fasa penyusunan terutamanya berkaitan dengan templat DOM Pada masa ini, isu skop tidak terlibat, iaitu, tiada pemaparan data dilakukan Sebagai contoh, arahan ngRepeate mengubah templat melalui kompilasi , fungsi pautan akan dikembalikan, menimpa pautan yang ditakrifkan kemudiannya digunakan terutamanya untuk pemaparan data, yang dibahagikan kepada dua pautan: pra-pautan dan pasca pautan adalah terbalik. Pautan pasca menghuraikan bahagian dalaman dahulu, dan kemudian bahagian luaran Ini mempunyai kesan yang besar pada arahan adalah selamat kerana arahan juga boleh menyertakan arahan Pada masa yang sama, pautan memproses DOM sebenar, yang akan melibatkan isu prestasi dalam operasi DOM.
Kandungan yang diliputi dalam artikel ini tidak begitu universal, dan akan ada suplemen yang sepadan nanti. Saya harap semua orang juga boleh belajar dan membincangkan rangka kerja sudut.