This article mainly introduces what angular thinks after its first understanding of the angular framework, and summarizes some personal problems after its understanding of angular. If you need it, you can refer to the actual development needs at work, to get started with the angular framework. From the time when ijuju.com was tortured by various problems and concepts, to now, I have a certain understanding and understanding, and I feel it is necessary to summarize my own understanding. I hope I can bear it with you if it is not in place.
1. bidirectional data binding
Various MV ** frameworks are prevalent in the industry, and related frameworks are emerging. angular is one of them (MVVM ). In fact, the core issue of the MV ** framework is to separate the view layer from the model to reduce code coupling and separate data and performance, MVC, MVP, and MVVM share the same goal. The difference between them is how to associate the model layer and view.
How data flows at the model and view layers becomes the key issue. angular implements bidirectional data binding through dirty-check. The so-called two-way binding means that changes in the view can be reflected in the model layer, while changes in the model data can be reflected in the view. So how does angular achieve bidirectional binding? Why is it dirty-check? Let's start with an original front-end question:
Html:
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 () {// initialize this. appy (); // this. increase () ;}}; bindDate. initialize (); script
In the preceding example, there are two processes:
The view layer affects the model layer:Click the button on the page to increase the number of data count by 1.
The model layer reflects the view layer:After the count changes, it is reflected on the view layer through the apply function.
This is the data processing previously implemented using jquery, YUI, and other class libraries. The problems are obvious:
- Involves a large number of DOM operations;
- Tedious process;
- Code Coupling is too high to facilitate unit test writing.
Let's take a look at how angular processes data:
Step 1. Add watcher: it is the object to be checked when data changes and needs to be registered first.
// Simplified the source code in 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 );}
Step 2. dirty-check: When data in a scope changes, you need to traverse the $ watchers = [...]
$digest: function() { while (length--) { watch = watchers[length]; watch.fn(value, lastValue, scope); } }
In this way, two-way data binding is realized. Is the above implementation similar to custom events? The observer design mode or (publisher-subscriber) is used ).
2. Dependency Injection
All those who have used the spring framework know that Ioc and AOP are the two most important concepts in spring, and Ioc can inject dependency (DI) in it ), obviously, angular has a very strong background color.
Similarly, first, let's look at how to solve the mutual dependency between objects without DI:
function Car() { ...} Car.prototype = { run: function () {...}} function Benz() { var cat = new Car(); }Benz.prototype = { ...}
In the above example, class Benz depends on class Car and solves this dependency directly through internal New. The disadvantages of doing so are obvious, and the code coupling becomes high, which is not conducive to maintenance. The backend framework was aware of this problem for a long time. spring registered the dependency between objects in the xml file in the early stage, and later solved the DI problem more conveniently through anotation, COS end users can look at the back-end code.
The js language itself does not have an annotation mechanism. How does angular implement it?
1. Simulate Annotation
// Annotation 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. Create an injection object
Function createInjector (modulesToLoad, strictDi) {// create an object 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. Get the injection object
Function invoke (fn, self, locals, serviceName) {var args = [], $ inject = annotate (fn, strictDi, serviceName); (...) {key = $ inject [I]; // replace it with the dependent object args. push (locals & locals. hasOwnProperty (key )? Locals [key]: getService (key, serviceName);} if (isArray (fn) {fn = fn [length];} return fn. apply (self, args );}
Here, is there a lot of backend framework design ideas that can be simulated without anotation, no wonder PPK says angular is "a front-end framework by non-front-enders for non-front-enders"
3. controller Communication
In actual development, the application system will be very huge. An application app cannot only have one controller, so communication may exist between different controllers. How can we solve this common problem, there are two main methods:
1. event mechanism:Register the event on $ rootScope. The problem is that it is too big to register on $ rootScope, which will cause some column follow-up problems.
//controller1app.controller('controller1', function ($rootScope) { $rootScope.$on('eventType', function (arg) { ...... }) })// controller2app.controller('controller2', function ($rootScope) { $rootScope.$emit('eventType',arg); or $rootScope.$broadcast('eventType',arg); })
2. Use service:Make full use of angular DI and service as a singleton to bridge different controllers.
// Register serviceapp. service ('message', function () {return {count: void (0) ;}}) // controller1, modify the count value of service app. controller ('controller1', function ($ scope, Message) {$ scope. count = 1; Message. count = $ scope. count;}); // controller2, get the count value of the service app. controller ('controller2', function ($ scope, Message) {$ scope. num = Message. count ;});
4. service Features
1. singleton ):In angular, only services can perform DI, such as controller and directive. Services provide some basic services literally and are not associated with specific services, controller and directive are closely related to specific services, so service uniqueness must be ensured.
2. lazy new:Angular first generates the provider of the service, but does not immediately generate the corresponding service. The instantiation operation is only performed when these services are required.
3. provider) category:Provider (), factory, service, value, and constant. provider is the underlying implementation. Other methods are based on the syntax sugar (sugar ), note that the $ get method must be added to these services, because the specific service is generated by executing the $ get method.
5. directive implementation
Directive compilation (compiler) includes two phases: compile and link. Simply put, the compile stage mainly deals with the template DOM, which does not involve scope issues, that is, no Data Rendering. For example, the ngRepeate command modifies the template through compile, after compile is executed, the link function is returned, covering the link function defined later. The link function is mainly used for Data Rendering, which is divided into pre-link and post-link, the order of parsing the two links is the opposite. post-link is to resolve the internal link and then the external link. Therefore, the parsing of directive is safe, because direve ve can also include directive, at the same time, link is the processing of real DOM, which will involve the performance of DOM operations.
The content involved in this article is not very universal and will be supplemented later. I hope you can also study the angular framework.