Angular view performance related to ng-app/ng-controller placement in DOM

542 views Asked by At

I was wondering whether I could gain any significant performance difference in my Angular app (specifically view processing) if I change ng-app and ng-controller attribute placement from i.e. body to some inner-page block element with much smaller DOM subtree?

Suppose I have a very long page with huge amount of content, but only part of it is Angular powered. Everything else is either server generated which means it's somewhat static from the client-side PoV.

Would it be better to put ng-app/ng-controller on only that subnode where Angular actually executes or would it be the same if I put them on body element of this very long page?

Does Angular process the view only of the sub-DOM where ng-app/ng-controller are defined or does it process the whole DOM anyway?

Is there any proof about this or even Angular documentation?

3

There are 3 answers

0
DRobinson On BEST ANSWER

Theoretically/Potentially? Yes, as New Dev mentions, the bootstrap function will have a larger DOM to run compile on, which would take longer than compiling a smaller tree.

Practically? Probably not. But your best bet is to benchmark your own page.

As an experiment, you can try the following. I generated a simple random DOM and injected it into a JSFiddle with console.time starting at script load, and ending when the controller is ready. There's a small sub-tree beside (as a sibling) a much larger, 5000-node tree.

Here's the fiddle wrapping the entire body: http://jsfiddle.net/gruagq8d/

And here's the fiddle where only the small subset is used: http://jsfiddle.net/h0hod2j8/

For me, running either of those fiddles repeatedly converges on about 260ms.

I've also tried running similar code on real webpage sources, such as StackOverflow itself, and found the same results (however I did not publish any of these because publishing other people's real pages to JSFiddle does not feel proper without permission) - you can try this for yourself pretty trivially.

Admittedly, this doesn't follow great benchmarking methodology, but if wrapping lots of additional DOM nodes caused significant different performance I'd still expect at least some difference in these.

I don't think that the additional compile time is an issue; for small DOMs it's obviously fast, and for large DOM is very relevant compared to the time it takes your browser to build the DOM in the first place.

All said, as mentioned before, your best option is to try to run similar benchmarks with your own page.

EDIT: Modifying the same benchmark to test digest cycles shows that there's no significant difference in those as well:

Wrapping minimal: http://jsfiddle.net/fsyfn1ee/

Wrapping whole DOM: http://jsfiddle.net/04tdwxhp/

2
Kirill Slatin On

Official docs say that only portion that is wrapped into ng-app directive is compiled.

If the ng-app directive is found then Angular will:

  • load the module associated with the directive.
  • create the application
  • injector compile the DOM treating the ng-app directive as the root of the compilation. This allows you to tell it to treat only a portion of the DOM as an Angular application.

This is pretty much expected as Angular allows to have several Angular modules controlling independent parts of one page (requires manual bootstrapping as pointed by Josiah Keller in comments). And their scopes will not interfere.

However adding extra static html (not angular bound) affect performance only at bootstrap. Yes angular has to compile all that elements at bootstrap to learn whether it should deal with them later.
But run-time performance is mostly affected by $watchs. Implicit form of creating them is to do bindings. So the more bindings you have overall, the longer each $digest cycle takes. And gives a general feeling of slow app. I've met a sensible threshold of 2k watches for modern browser/CPUs

2
New Dev On

ng-app really just specifies the root element on which Angular calls angular.bootstrap. bootstrap starts a "compilation" process, which is to say that it goes over each DOM element in the subtree of the root and collects directives from it and links them.

Right there, you can see the benefit of restricting the app to a smaller subtree of the DOM:

  1. Compilation process is slightly faster
  2. Less directives are compiled (e.g. <input> elements that should not be part of the app are not compiled/linked).

The thing to remember is that it is the $digest cycle that is the significant source of performance problems/opportunities for optimizations - that is, the number of $watchers and how fast the "$watchers" are.