|  | 
| 3 | 3 | Here you will find a collection of tools and tips for keeping your application | 
| 4 | 4 | perform well and contain fewer bugs. | 
| 5 | 5 | 
 | 
|  | 6 | +## Angular debug tools in the dev console | 
|  | 7 | + | 
|  | 8 | +Angular provides a set of debug tools that are accessible from any browser's | 
|  | 9 | +developer console. In Chrome the dev console can be accessed by pressing | 
|  | 10 | +Ctrl + Shift + j. | 
|  | 11 | + | 
|  | 12 | +### Enabling debug tools | 
|  | 13 | + | 
|  | 14 | +By default the debug tools are disabled. You can enable debug tools as follows: | 
|  | 15 | + | 
|  | 16 | +```dart | 
|  | 17 | +import 'package:angular2/tools.dart'; | 
|  | 18 | +
 | 
|  | 19 | +main() { | 
|  | 20 | +  var appRef = await bootstrap(Application); | 
|  | 21 | +  enableDebugTools(appRef); | 
|  | 22 | +} | 
|  | 23 | +``` | 
|  | 24 | + | 
|  | 25 | +### Using debug tools | 
|  | 26 | + | 
|  | 27 | +In the browser open the developer console (Ctrl + Shift + j in Chrome). The | 
|  | 28 | +top level object is called `ng` and contains more specific tools inside it. | 
|  | 29 | + | 
|  | 30 | +Example: | 
|  | 31 | + | 
|  | 32 | +```javascript | 
|  | 33 | +ng.profiler.timeChangeDetection(); | 
|  | 34 | +``` | 
|  | 35 | + | 
| 6 | 36 | ## Code size | 
| 7 | 37 | 
 | 
| 8 | 38 | Code needs to be downloaded, parsed and executed. Too much code could lead to | 
| @@ -145,3 +175,110 @@ transformers: | 
| 145 | 175 |     - --trust-type-annotations | 
| 146 | 176 |     - --trust-primitives | 
| 147 | 177 | ``` | 
|  | 178 | + | 
|  | 179 | +## Performance | 
|  | 180 | + | 
|  | 181 | +### Change detection profiler | 
|  | 182 | + | 
|  | 183 | +If your application is janky (it misses frames) or is slow according to other | 
|  | 184 | +metrics it is important to find the root cause of the issue. Change detection | 
|  | 185 | +is a phase in Angular's lifecycle that detects changes in values that are | 
|  | 186 | +bound to UI, and if it finds a change it performs the corresponding UI update. | 
|  | 187 | +However, sometimes it is hard to tell if the slowness is due to the act of | 
|  | 188 | +computing the changes being slow, or due to the act of applying those changes | 
|  | 189 | +to the UI. For your application to be performant it is important that the | 
|  | 190 | +process of computing changes is very fast. For best results it should be under | 
|  | 191 | +3 milliseconds in order to leave room for the application logic, the UI updates | 
|  | 192 | +and browser's rendering pipeline to fit withing the 16 millisecond frame | 
|  | 193 | +(assuming the 60 FPS target frame rate). | 
|  | 194 | + | 
|  | 195 | +Change detection profiler repeatedly performs change detection without invoking | 
|  | 196 | +any user actions, such as clicking buttons or entering text in input fields. It | 
|  | 197 | +then computes the average amount of time it took to perform a single cycle of | 
|  | 198 | +change detection in milliseconds and prints it to the console. This number | 
|  | 199 | +depends on the current state of the UI. You will likely see different numbers | 
|  | 200 | +as you go from one screen in your application to another. | 
|  | 201 | + | 
|  | 202 | +#### Running the profiler | 
|  | 203 | + | 
|  | 204 | +Enable debug tools (see above), then in the dev console enter the following: | 
|  | 205 | + | 
|  | 206 | +```javascript | 
|  | 207 | +ng.profiler.timeChangeDetection(); | 
|  | 208 | +``` | 
|  | 209 | + | 
|  | 210 | +The results will be printed to the console. | 
|  | 211 | + | 
|  | 212 | +#### Recording CPU profile | 
|  | 213 | + | 
|  | 214 | +Pass `{record: true}` an argument: | 
|  | 215 | + | 
|  | 216 | +```javascript | 
|  | 217 | +ng.profiler.timeChangeDetection({record: true}); | 
|  | 218 | +``` | 
|  | 219 | + | 
|  | 220 | +Then open the "Profiles" tab. You will see the recorded profile titled | 
|  | 221 | +"Change Detection". In Chrome, if you record the profile repeatedly, all the | 
|  | 222 | +profiles will be nested under "Change Detection". | 
|  | 223 | + | 
|  | 224 | +#### Interpreting the numbers | 
|  | 225 | + | 
|  | 226 | +In a properly-designed application repeated attempts to detect changes without | 
|  | 227 | +any user actions should result in no changes to be applied on the UI. It is | 
|  | 228 | +also desirable to have the cost of a user action be proportional to the amount | 
|  | 229 | +of UI changes required. For example, popping up a menu with 5 items should be | 
|  | 230 | +vastly faster than rendering a table of 500 rows and 10 columns. Therefore, | 
|  | 231 | +change detection with no UI updates should be as fast as possible. Ideally the | 
|  | 232 | +number printed by the profiler should be well below the length of a single | 
|  | 233 | +animation frame (16ms). A good rule of thumb is to keep it under 3ms. | 
|  | 234 | + | 
|  | 235 | +#### Investigating slow change detection | 
|  | 236 | + | 
|  | 237 | +So you found a screen in your application on which the profiler reports a very | 
|  | 238 | +high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable | 
|  | 239 | +recording while profiling: | 
|  | 240 | + | 
|  | 241 | +```javascript | 
|  | 242 | +ng.profiler.timeChangeDetection({record: true}); | 
|  | 243 | +``` | 
|  | 244 | + | 
|  | 245 | +Then look for hot spots using | 
|  | 246 | +[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling). | 
|  | 247 | + | 
|  | 248 | +#### Reducing change detection cost | 
|  | 249 | + | 
|  | 250 | +There are many reasons for slow change detection. To gain intuition about | 
|  | 251 | +possible causes it would help to understand how change detection works. Such a | 
|  | 252 | +discussion is outside the scope of this document (TODO link to docs), but here | 
|  | 253 | +are some key concepts in brief. | 
|  | 254 | + | 
|  | 255 | +By default Angular uses "dirty checking" mechanism for finding model changes. | 
|  | 256 | +This mechanism involves evaluating every bound expression that's active on the | 
|  | 257 | +UI. These usually include text interpolation via `{{expression}}` and property | 
|  | 258 | +bindings via `[prop]="expression"`. If any of the evaluated expressions are | 
|  | 259 | +costly to compute they could contribute to slow change detection. A good way to | 
|  | 260 | +speed things up is to use plain class fields in your expressions and avoid any | 
|  | 261 | +kinds of computation. Example: | 
|  | 262 | + | 
|  | 263 | +```dart | 
|  | 264 | +@View( | 
|  | 265 | +  template: '<button [enabled]="isEnabled">{{title}}</button>' | 
|  | 266 | +) | 
|  | 267 | +class FancyButton { | 
|  | 268 | +  // GOOD: no computation, just return the value | 
|  | 269 | +  bool isEnabled; | 
|  | 270 | +
 | 
|  | 271 | +  // BAD: computes the final value upon request | 
|  | 272 | +  String _title; | 
|  | 273 | +  String get title => _title.trim().toUpperCase(); | 
|  | 274 | +} | 
|  | 275 | +``` | 
|  | 276 | + | 
|  | 277 | +Most cases like these could be solved by precomputing the value and storing the | 
|  | 278 | +final value in a field. | 
|  | 279 | + | 
|  | 280 | +Angular also supports a second type of change detection - the "push" model. In | 
|  | 281 | +this model Angular does not poll your component for changes. Instead, the | 
|  | 282 | +component "tells" Angular when it changes and only then does Angular perform | 
|  | 283 | +the update. This model is suitable in situations when your data model uses | 
|  | 284 | +observable or immutable objects (also a discussion for another time). | 
0 commit comments