Optimize performance for angular applications

Source: Internet
Author: User

The performance of the MVVM framework, in fact, depends on several factors:

    • Number of Monitors

    • How data changes are detected and bound

    • Performance of indexes

    • The size of the data

    • Structure of the data

We want to optimize the performance of the angular project, but also need to start from these aspects.

1. Reduce the number of monitoring values

How do you reduce the number of monitoring values?

Consider the extreme situation, when not introduced angular, the number of monitoring is 0, whenever we have the need to bind the data item, the monitoring value is generated.

We noticed that the angular used an HTML template syntax to do the binding and that it was very convenient to develop business projects, but consider that this so-called "template" is actually different from the template that we are familiar with.

The traditional template, is a static template, the data into the template after the generation of the interface, then the data changes, the interface will not change. However, the angular "template" is dynamic, when the interface is generated, the data generated changes, the interface will be updated.

This is the advantage of angular, but sometimes we will increase the trouble because of improper use. Because angular uses a change detection method to track changes in data, these things are burdensome, and many times, some data will not change after initialization, but because we do not differentiate them, angular still want to generate a listener to track this part of the data changes, The performance is also subject to tie.

In this case, you can use a single binding, which binds the data only at initialization time, with the following syntax:

<div>{{::item}}</div>

<ul>

<li ng-repeat= "item in:: Items" >{{item}}</li>

</ul>

Such data will not be continuously observed, it will effectively reduce the number of monitoring values, improve performance.

2. Reduce the cost of data alignment

This link starts with the way data changes are detected and bound. The details do not say too much, have said before. From the data to the interface of the update, generally in two ways: push, pull.

The so-called push, is in the set when the initiative to update the relevant data, most of the framework is this way, the lower version of the browser with Definesetter and so on.

function Employee () {

This._firstname = "";

This._lastname = "";

This.fullname = "";

}

Employee.prototype = {

Get FirstName () {

return this._firstname;

},

Set FirstName (val) {

This._firstname = val;

This.fullname = val + "" + this.lastname;

},

Get LastName () {

return this._lastname;

},

Set LastName (val) {

This._lastname = val;

This.fullname = This.lastname + "" + val;

}

};

The so-called pull, is set when the time only to change themselves, the associated data until the use of their own to fetch. Like what:

function Employee () {

This.firstname = "";

This.lastname = "";

}

Employee.prototype = {

Get FullName () {

return this.firstname + "" + this.lastname;

}

};

In some frameworks, both methods are available. At this time, you can consider the appropriate way to use, for example, may be some of the framework is a merger change, batch update, may be used to pull the way of high efficiency;

The above code can be seen, from the simplicity of code writing, pull mode is much simpler than push mode, if you can predict the volume of small data, can be used.

In the actual development process, these two methods need to be weighed. Our example is simple, if a property depends on a lot of things, for example, a large shopping list, there is a total price, it is the price of each commodity multiplied by the number of purchases, and then added up.

In this case, if you are using pull mode, which is to make this change on the get of the total price, it needs to traverse the entire array and recalculate. However, if the use of push mode, each time there is a commodity price or the number of goods purchased changes, as long as the original total price, minus two changes in the difference.

In addition, different frameworks use different ways to detect changes in data, such as angular, if an element in an array changes, how does it know that the array has changed?

It needs to keep the data before the change, and then make the comparison:

    • First, if the reference to the array is equal, this step is to detect the overall assignment of the arrays, such as This.arr = [1, 2, 3]; Directly replace the original, if this happens, think it must have changed. (In fact, if the content is the same as the original, it can be considered unchanged, but because the internal implementation of these frameworks, often need to update the data and DOM elements of the index relationship, so not)

    • Second, compare the length of the array, if the length is not equal to the original, it must have changed.

    • And then we're going to be able to change the elements.

Therefore, some people will consider the combination of immutable such things in the angular, speed up the decision process of the change, because the immutable of the data as long as any change, its reference will certainly change, so long as the first step to determine the reference is sufficient to know whether the data has changed.

Some people say that your decision to reduce the cost is not big ah, because the introduction of immutable to increase the cost of replication, with the new and old data here compared to the cost, but also less than where to go. But this place to note, angular in the event of the time, will be all the monitoring data is re-alignment, that is, if you have a large array in the interface, you have never re-assigned to it, but often in another very small form of the binding data on the update, the array is to be compared, This is compared to the pit, so if the introduction of immutable, can greatly reduce the normal time of the non-impact cost.

However, the introduction of immutable will also affect the entire application, the need to use the immutable in each assignment value, but also at the time of binding, the data is unpacked, because the angular bound data is pojo.

Therefore, it is prudent to use this approach, unless the framework itself is built on the basis of immutable. Perhaps, we can expect a set of parallel with the Ng-model mechanism, ng-immutable and the like, the difficulty of implementation is still quite large.

In the case of using ES5, some methods can be used to speed up judgments, such as arrays:

    • Filter

    • Map

    • Reduce

They are able to return a completely new array, which is not equal to the original reference, so the result can be determined in the first step, without the need to proceed to the next few steps of comparison.

However, the optimization of this link is not obvious, the most critical optimization is the matching of the index optimization, see the next section.

3. Improving the performance of indexes

In angular, the traversal of an array or an object can be accomplished through ng-repeat, but there are many tricks to this traversal mechanism.

When using arrays of simple types, we are likely to encounter a problem: the same values exist in the array, such as:

This.arr = [1, 3, 5, 3];

<ul>

<li ng-repeat= "num in arr" >{{num}}</li>

</ul>

This time will be an error, and then if you go to search, you will find a solution:

<ul>

<li ng-repeat= "num in arr $index" >{{num}}</li>

</ul>

Why is this going to work?

Let's think about it, if we implement a function like angular, because we have to correlate the DOM with the data so that when the data is changed, it can be refreshed to the corresponding interface, so there must be a mapping relationship.

The mapping relationship requires a unique index, and in that case, angular defaults to using its own index for simple types, and when duplicates occur, it goes wrong. If you specify $index, which is the index of the element's subscript in the array, you can avoid this problem.

So, what about an array of objects?

For example such an array, we bind in a different two ways:

Function Listctrl () {

    this.arr = [];

    for (var i=0; i10000; i++) {

         This.arr.push ({

            id:i,

            label: "Item" + I

         });

    }

 

    var time = new Date ();

     $timeout (function () {

        alert ( New Date ()-time);

        console.log (this.arr[0]);

    }.bind (this), 0);

}

<ul ng-controller= "Listctrl as Listctrl" >

<li ng-repeat= "item in Listctrl.arr" >{{item}}</li>

</ul>

<ul ng-controller= "Listctrl as Listctrl" >

<li ng-repeat= "item in Listctrl.arr track by Item.id" >{{item}}</li>

</ul>

Look at the example address and click a few more clicks:

We were surprised to find that there were no differences between the two times.

Looking at the data in arr after the binding, it was found that the original data was changed without the track by $index, and some index information was added, which is an important clue that angular can find the associated interface when the data is changed.

Object {id:0, Label: "Item 0", $ $hashKey: "Object:4"}

If we know what guarantees the uniqueness of the data and manually specify it as an index, you can reduce the unnecessary process of adding an index.

4. Reduce the size of your data

It may be strange to see this headline. The size of the business data is not controlled by the programmer, how to reduce it? The reduction here refers to reducing the size of the data that is used to bind to the interface.

The size of the data also affects the binding efficiency, we consider a screen can show limited data, do not need to show everything immediately, can be intercepted from the data for a display, such as the familiar data paging is one way.

A very traditional kind of data paging, there will be a paging bar, which says how much data, then the previous page, the next page, so switch. Later, some variants were introduced, such as rolling loads, when the scroll bars were rolled to the bottom, and then loaded or generated a new interface.

If we have a list of tens of thousands of data, but we're not going to put a page bar in that old 圡 way, how do you get a balance between performance and experience?

People who have contacted Adobe Flex may be impressed with the list control, because even if you give it millions of data, it won't slow down, why? Because its scroll bar is false.

Similarly, we may use the DOM in the browser to simulate a scrollbar, and then use the position of the scroll bar to get the corresponding piece of data from the full amount of data, and bind the rendering to the interface.

This technique, commonly referred to as virtual list, has a third-party implementation in many frameworks, as described in this article: AngularJS Virtual list Directive Tutorial

The above article does just the preliminary optimization, not fine, because it assumes that the size of all items in the list is consistent, and is predictable at the time of creation, so it's not flexible. If finer optimizations are needed, you need to do a real-time measurement, measure each child that has been created and rendered, and then update the position of the scroll area.

See DEMO:HTTP://CODEPEN.IO/XUFEI/PEN/AVRJQV

5. Flattening the structure of the data

So how does the structure of the data affect the efficiency of execution? I give a common example is the tree structure, the structure of the General people will use a structure such as UL and Li, and then inevitably in a recursive way to use the MVVM framework.

Let's think about it, why do we have to use this way? There are two reasons:

    • A given data structure is a tree-shaped

    • We are accustomed to using tree-shaped dom structures to express tree data

What is this tree-shaped data for us? is the data model. But we know that compared to the two tree structure is very troublesome, its hierarchy makes monitoring complex, whether it is the data one by one, or the accessor, or just canceled observe proposal, will be more than the single-layer data more troublesome.

What if we want to show it in a more flat DOM structure, rather than a hierarchical structure? The so-called tree-shaped DOM structure, can show us nothing but the position of the offset, such as all subordinate nodes more right than the superior, these things can be easily used to simulate the positioning, so that it is possible to apply the lateral DOM structure to express the shape of the tree.

Remember, MVVM, what do these letters mean?

Model View ViewModel

We looked at the first two, but never focused on the view model. In many people's eyes, the view model is just a simple package of the model, in fact, it is only a special case, angular official demo form this misleading. The real role of the view model should include: transforming the model into a format suitable for the view presentation.

If we need to have a relatively flat data structure at the view level, we have to flatten the raw data at this level, for a chestnut, we're going to make a dynamic organization chart, which will be like a tree, there will certainly be a tree-shaped data structure, but we can maintain both the tree and the flat structure, and always keep in sync.

The original data is as follows:

var Source = [

{ID: "0", Name: "A"},

{ID: "1", Name: "B"},

{ID: "013", Name: "Abd", Parent: "01"},

{ID: "2", Name: "C"},

{ID: "3", Name: "D"},

{ID: "XX", Name: "AA", Parent: "0"},

{ID: "-", Name: "AB", Parent: "0"},

{ID: "" "," Name: "AC," Parent: "0"},

{ID: "010", Name: "ABA", Parent: "01"},

{ID: "011", Name: "ABB", Parent: "01"},

{ID: "012", Name: "ABC", Parent: "01"}

];

The conversion code is as follows:

var map = {};

var dest = [];

Source.foreach (function (IT) {

Map[it.id] = it;

});

Source.foreach (function (IT) {

if (! It.parent) {

Root node

Dest.push (IT);

}

else {

Leaf node

Map[it.parent].children = Map[it.parent].children | | [];

Map[it.parent].children.push (IT);

}

});

The converted Dest becomes this:

[

{

"id": "0",

"Name": "A",

"Children": [

{

"id": "00",

"Name": "AA",

"Parent": "0"

},

{

"id": "01",

"Name": "AB",

"Parent": "0",

"Children": [

{

"id": "013",

"Name": "Abd",

"Parent": "01"

},

{

"id": "010",

"Name": "ABA",

"Parent": "01"

},

{

"id": "011",

"Name": "ABB",

"Parent": "01"

},

{

"id": "012",

"Name": "ABC",

"Parent": "01"

}

]

},

{

"id": "02",

"Name": "AC",

"Parent": "0"

}

]

},

{

"id": "1",

"Name": "B"

},

{

"id": "2",

"Name": "C"

},

{

"id": "3",

"Name": "D"

}

]

We still use source when the interface is bound, and we use dest when we operate. Because, when binding, do not have to go through deep detection, and operation, need to have a parent-child relationship to make the operation convenient.

For example, if we want to make a tree topology, or a product such as Mindmap, if this is not the case, it is likely that the interface structure will be directly bound to the tree data, when the efficiency will be relatively low.

But we can also make this optimization:

    • While preserving flattened raw data, it also generates tree-like data

    • Bind the display structure to the flattened data

    • Whenever the structure changes, the tree data is updated and the interface coordinates are calculated inside the data model

    • Flat data showing the structure because it is the same reference as the tree data, it is also updated, which causes the interface refresh

    • At this time, the interface is a single-layer refresh, no need to track the level of data, efficiency can be improved a lot, especially when the depth of the layer

6. Summary

The meaning of MVVM's existence is to maximize development efficiency, and only in extreme cases is it worth optimizing performance. If you have a lot of performance problems in your scene, it is likely that the business pattern of such a framework is not suitable.

Summarize some of our optimization methods, their mechanisms are:

    • Reduce monitoring items

    • Speed up change detection

    • Actively set the index

    • Reduce the amount of data rendered

    • Flattening of the data

As you can see, all of our optimizations are at the data level without having to deliberately optimize the interface. If you use an MVVM framework and do a lot of optimizations for it, it's better not to use it and write it all by hand.

For other MVVM frameworks, it can be roughly similar in several ways, except that some of the details are different and can be comprehend by analogy.

This article transfers from Xu Fei (@ The essence of Migrant Workers v) website: https://github.com/xufei/blog/issues/23
If there is infringement, please contact the public number: the number of smooth link, will be the first time to delete.

Optimize performance for angular applications

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.