AngularJs Performance Optimization English original (personal backup use)

Source: Internet
Author: User
Tags scalyr

Optimizing angularjs:1200ms to 35msby Steven czerwinksi

Edit:due to the level of interest, we ' ve released the source code to the work described here:https://github.com/scalyr/a Ngular.

Here at Scalyr, we recently embarked to a full rewrite of our web client. Our application are a broad-spectrum monitoring and log analysis tool. Our Home-grown log database executes most queries in tens of milliseconds, but each interaction required a page load, Taki Ng several seconds for the user.

A single-page Application architecture promised to unlock the backend ' s blazing performance, so we began sear Ching for the appropriate framework, and identified AngularJS as a promising candidate. Following the "Fail fast" principle, we began with our toughest challenge, the log view.

This was a real acid test for the application framework. The user can click on any word to search for related log messages, so there is thousands of clickable elements on the Page Yet we want instantaneous response for paging through the log. We were already prefetching the next page of log data, so the user interface update is the bottleneck. A straightforward AngularJS implementation of the log view took 1.2 seconds to advance to the next page, but with some car Eful optimizations we were able to reduce this to milliseconds. These optimizations proved to being useful in other parts of the application, and fit in well with the AngularJS philosophy, Though we had to break few rules to implement them. In this article, we ll discuss the techniques we used.

A Log of Github updates from our live demo.An AngularJS log viewer

At heart, the log View is simply a list of log messages. Each word was clickable, and so must was placed in its own DOM element. A simple implementation in AngularJS might look like this:

<span class= ' logline ' ng-repeat= ' line in Loglinestoshow ' ><span class= ' logtoken ' ng-repeat= ' tokens in line ' > {{token | formattoken}} </span><br></span>

One page can easily has several thousand tokens. In our early tests, we found this advancing to the next log page could take several agonizing seconds of JavaScript Execut Ion. Worse, unrelated actions (such as clicking on a navigation dropdown) now had noticeable lag. The conventional wisdom for AngularJS says so you should keep the number of data-bound elements below 200. With a element per word, we were far above.

Analysis

Using Chrome's Javascript Profiler, we quickly identified the sources of lag. First, each update spent a lot of time creating and destroying DOM elements. If The new view has a different number of lines, or any line has a different number of words, Angular ' s ng-repeat directiv E'll create or destroy DOM elements accordingly. This turned is quite expensive.

Second, each of the word had its own change watcher, which AngularJS would invoke on every mouse click. This is causing the lag on unrelated actions like the navigation dropdown.

Optimization #1: Cache DOM elements

We created a variant of the Ng-repeat directive. In we version, when the number of the data elements was reduced, the excess DOM elements is hidden and not destroyed. If the number of elements later increases, we re-use these cached elements before creating new ones.

Optimization #2: Aggregate watchers

All this time spent invoking change watchers is mostly wasted. In we application, the data associated with a particular word can never change unless the overall array of log messages C Hanges. To address this, we created a directive that ' hides ' the change watchers of it children, allowing them to being invoked only When the value of a specified parent expression changes.  With the change, we avoided invoking thousands of Per-word the change watchers on every mouse click or other minor event. (To accomplish this, we had-slightly break the AngularJS abstraction layer. We'll say a bit more on this conclusion.)

Optimization #3: Defer element creation

As noted, we create a separate DOM element for each word in the log. We could get the same visual appearance with a single DOM element per line; The extra elements is needed only for mouse interactivity. Therefore, we decided to defer the creation of Per-word elements for a particular line until the mouse moves over that Lin E.

To implement this, we create the versions of each line. One is a simple text element, showing the complete log message. The other is a placeholder which would eventually be populated with an element per word. The placeholder is initially hidden. When the mouse moves-over, the placeholder are shown and the simple version is hidden. Showing the placeholder causes it to being populated with word elements, as described next.

Optimization #4: Bypass watchers for hidden elements

We created one more directive, which prevents watchers from being executed for a element (or its children) when the Eleme NT is hidden. This supports optimization #1, eliminating any overhead for extra DOM nodes which has been hidden because we currently ha ve more DOM nodes than data elements. It also supports optimization #3, making it easy to defer the creation of PER-WORD nodes until the tokenized version of th E line is shown.

Here is, the code looks like with all these optimizations applied. Our custom directives is shown in bold.

<span class= ' logline '  sly-repeat= ' line in Loglinestoshow '  sly-evaluate-only-when= ' loglines ' ><div ng-mouseenter= "mousehasentered = true" ><span ng-show= '! Mousehasentered ' >{{logline | formatline}} </span><div ng-show= ' mousehasentered '   Sly-prevent-evaluation-when-hidden><span class= ' logtoken '  sly-repeat= ' tokens in line ' >{{token | Formattoken}}</span></div></div>

 

<br>

</span>

Sly-repeat is our variant of ng-repeat, which hides extra DOM elements rather than destroying them. Sly-evaluate-only-when prevents inner change watchers from executing unless the "loglines" variable changes, indicating th At the user have advanced to a new section of the log. And Sly-prevent-evaluation-when-hidden prevents the inner repeat clause from executing until the mouse moves over this Lin E and the div is displayed.

This shows the power of AngularJS for encapsulation and separation of concerns. We ' ve applied some fairly sophisticated optimizations without much impact on the structure of the template. (This isn ' t the exact code we ' re using in production, but it captures all of the important elements.)

Results

To evaluate performance, we added code to measure the time from a mouse click, until Angular ' s $digest cycle finishes (MEA Ning that we are finished updating the DOM). The elapsed time is displayed in a widget on the side of the page. We measured performance of the "Next page" button while viewing a Tomcat access log, using Chrome on a recent MacBook Pro. Here's the results (each number is the average of trials):

Data already Cached Data fetched from server
Simple AngularJS 1190 MS 1300 MS
With optimizations Ms 201 ms

These figures do not include the time the browser spends in DOM layout and repaint (after JavaScript execution have finishe D), which is around-milliseconds in each implementation. Even so, the difference is dramatic; Next Page time dropped from a "stately" 1.2 seconds, to an imperceptible (all MS with rendering).

The ' data fetched from server ' figures include time for a AJAX call to our backend to fetch the log data. This was unusual for the next page button, because we prefetch the next page of logs, but could be applicable for other UI in Teractions. But even here, the optimized version updates almost instantly.

Conclusion

This code had been in production for both months, and we ' re very happy with the results. You can see it on action at the Scalyr Logs demo site. After entering the demo, click on the "Log View" link, and play with the Next/prev buttons. It's so fast and you'll find it hard-believe you ' re seeing live data from a real server.

Implementing these optimizations in a clean manner is a fair amount of work. It would has been simpler to create a single custom directive this directly generated all of the HTML for the log view, b Ypassing Ng-repeat. However, this would has been against the spirit of AngularJS, bearing a cost in code maintainability, testability, and OT Her considerations. Since The log view was and our test project for AngularJS, we wanted to verify that a clean solution was possible. Also, the new directives we created has already been used in other parts of our application.

We did our best to follow the Angular philosophy, and but we do have to bend the AngularJS Abstraction layer to implement SOM E of these optimizations. We overrode the Scope ' s $watch method to intercept watcher registration, and then had to do some careful manipulation of s Cope ' s instance variables to control which watchers is evaluated during a $digest.

Next time

This article covered a set of techniques we used to optimize JavaScript execution time in our AngularJS port. We ' re big believers in pushing performance to the limit, and these is just some of the tricks we ve used. In upcoming articles, we'll describe techniques to reduce network requests, network latency, and server execution time. We may also discuss our general experience with AngularJS and the approach we took to structuring our application Code-i f you ' re interested in this, let us know in the comments. For more discussion on AngularJS performance, you can also read this article by Gleb Bahmutov.

Obligatory plug

At Scalyr, we ' re all about improving the DEVOPS experience through better technology. If you've read this far, you should probably read more about the Scalyr Log management tool.

AngularJs Performance Optimization English original (personal backup use)

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.