docs: copyedit DART_TOOLS.md

This commit is contained in:
Kathy Walrath 2015-09-22 17:28:08 -07:00 committed by Yegor Jbanov
parent 4d4d20edb9
commit 4087e3115b
1 changed files with 100 additions and 60 deletions

View File

@ -1,52 +1,77 @@
# Developer Tools for Dart # Developer Tools for Dart
Here you will find a collection of tools and tips for keeping your application Use these tools and techniques to increase your app's performance
perform well and contain fewer bugs. and reliability.
## Angular debug tools in the dev console * [Angular debugging tools](#angular-debugging-tools)
* [Code size](#code-size)
* [Performance](#performance)
Angular provides a set of debug tools that are accessible from any browser's
developer console. In Chrome the dev console can be accessed by pressing
Ctrl + Shift + j.
### Enabling debug tools ## Angular debugging tools
By default the debug tools are disabled. You can enable debug tools as follows: Starting with alpha.38, Angular provides a set of debugging tools
that are accessible from any browser's developer console.
In Chrome, you can get to the dev console by pressing
Ctrl + Shift + J (on Mac: Cmd + Opt + J).
### Enabling the debugging tools
By default the debugging tools are disabled.
Enable the debugging tools as follows:
```dart ```dart
import 'package:angular2/tools.dart'; import 'package:angular2/tools.dart';
main() { main() async {
var appRef = await bootstrap(Application); var appRef = await bootstrap(Application);
enableDebugTools(appRef); enableDebugTools(appRef);
} }
``` ```
### Using debug tools <!-- Change function name to enableDebuggingTools? -->
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
top level object is called `ng` and contains more specific tools inside it.
Example: ### Using the debugging tools
In the browser, open the dev console. The top-level object is called `ng` and
contains more specific tools inside it.
For example, to run the change detection profiler on your app:
<!-- QUESTION: is "on your app" accurate?
is "run the change detection profiler on your app" the best wording? -->
```javascript ```javascript
// In the dev console:
ng.profiler.timeChangeDetection(); ng.profiler.timeChangeDetection();
``` ```
The [Change detection profiler](#change-detection-profiler) section
has more details.
<!-- Point to API docs when they're published, if they're useful.
They should be under
http://www.dartdocs.org/documentation/angular2/latest
and/or
https://angular.io/docs/js/latest/api/. -->
## Code size ## Code size
Code needs to be downloaded, parsed and executed. Too much code could lead to Code must be downloaded, parsed, and executed. Too much code can lead to
slow application start-up time, especially on slow networks and low-end devices. slow application start-up time, especially on slow networks and low-end devices.
The tools below will help you identify contributors to code size and keep them The tools and techniques in this section can help you to identify
in check. unnecessarily large code and to reduce code size.
### Finding contributors to code size ### Finding contributors to code size
Options for investigating code size include the `--dump-info` dart2js option,
ng2soyc, `reflector.trackUsage()`, and code coverage information
from the Dart VM.
#### --dump-info #### --dump-info
`dart2js` has an option `--dump-info` that outputs information about what The `--dump-info` option of `dart2js` outputs information about what happened
happened during compilation. Enable this option in your transformer options during compilation. You can specify `--dump-info` in `pubspec.yaml`:
like this:
```yaml ```yaml
transformers: transformers:
@ -56,35 +81,39 @@ transformers:
- --dump-info - --dump-info
``` ```
Use the [visualizer](https://github.com/dart-lang/dump-info-visualizer) to The [Dump Info Visualizer](https://github.com/dart-lang/dump-info-visualizer)
analyze the output or any of the command-line tools documented can help you analyze the output.
[here](http://dart-lang.github.io/dart2js_info/doc/api/index.html). For more information, see the
[dart2js_info API reference](http://dart-lang.github.io/dart2js_info/doc/api/).
#### ng2soyc.dart #### ng2soyc.dart
[ng2soyc](https://github.com/angular/ng2soyc.dart) is a utility for analyzing [ng2soyc](https://github.com/angular/ng2soyc.dart) is a utility for analyzing
code size contributors in Angular 2 applications. It groups code size by code size contributors in Angular 2 applications. It groups code size by
library. It also assumes your library names follow library and, assuming your library names follow
"package.library.sub-library..." convention and gives code size breakdown at [standard naming conventions](https://www.dartlang.org/articles/style-guide/#do-prefix-library-names-with-the-package-name-and-a-dot-separated-path)
each level. To reduce noise in the output (for very large apps) it also provides (package.library.sublibrary...), gives the code size breakdown at
each level. To reduce noise in the output of very large apps, ng2soyc provides
an option to hide libraries that are too small, so you can focus on the biggest an option to hide libraries that are too small, so you can focus on the biggest
contributors. contributors.
#### Track unused reflection data #### Track unused reflection data
Call `reflector.trackUsage()` to cause it to track reflection information used <!-- QUESTION: How do you get access to reflector & ReflectionInfo? -->
Call `reflector.trackUsage()` to track reflection information used
by the application. Reflection information (`ReflectionInfo`) is a data by the application. Reflection information (`ReflectionInfo`) is a data
structure that stores information about your application that Angular uses for structure that stores information about your application that Angular uses for
locating DI factories, generated change detectors and other code related to a locating DI factories, generated change detectors and other code related to a
given type. After exercising your application, call `reflector.listUnusedKeys()` given type. After exercising your application, call `reflector.listUnusedKeys()`
to get a list of types and functions whose reflection information was retained to get a list of types and functions whose reflection information was retained
but was never used by the application. but never used by the application.
#### Use code coverage to find dead code #### Use code coverage to find dead code
When running in Dartium (or in Dart VM in general) you can request code When running in Dartium (or in the Dart VM, in general) you can request code
coverage information from the VM. You can either use coverage information from the VM. You can either use
[observatory](https://www.dartlang.org/tools/observatory/), or download [observatory](https://www.dartlang.org/tools/observatory/) or download
the coverage file and use your own tools to inspect it. Lines of code that are the coverage file and use your own tools to inspect it. Lines of code that are
not covered are top candidates for dead code. not covered are top candidates for dead code.
@ -93,10 +122,16 @@ code, only necessary evidence. It is perfectly possible that you simply didn't
exercise your application in a way that triggers the execution of uncovered exercise your application in a way that triggers the execution of uncovered
code. A common example is error handling code. Just because your testing never code. A common example is error handling code. Just because your testing never
encountered an error does not mean the error won't happen in production. You encountered an error does not mean the error won't happen in production. You
therefore do not have to rush and remove all the `catch` blocks. therefore don't have to rush and remove all the `catch` blocks.
### Reducing code size ### Reducing code size
To reduce code size, you can disable reflection,
enable minification, and manually remove dead code.
You can also try less safe options such as
telling dart2js to trust type annotations.
#### Disable reflection #### Disable reflection
`dart:mirrors` allows discovering program metadata at runtime. However, this `dart:mirrors` allows discovering program metadata at runtime. However, this
@ -129,19 +164,19 @@ example:
/// This function decides which serialization format to use /// This function decides which serialization format to use
void setupSerializers() { void setupSerializers() {
if (server.doYouSupportProtocolBuffers()) { if (server.doYouSupportProtocolBuffers()) {
useProtobufSerializaers(); useProtobufSerializers();
} else { } else {
useJsonSerializaers(); useJsonSerializers();
} }
} }
``` ```
In this example the application asks the server what kind of serialization In this example the application asks the server what kind of serialization
format it uses and dynamically chooses one or the other. `dart2js` could never format it uses and dynamically chooses one or the other. `dart2js` can't
tell whether the server responds with yes or no and so it must retain both tell whether the server responds with yes or no, so it must retain both
kinds of serializers. However, you, as the developer of the application, may kinds of serializers. However, if you know that your server supports
know in advance that your server supports protocol buffers and so you could protocol buffers, you can remove that `if` block entirely and default to
remove that `if` block entirely and default to protocol buffers. protocol buffers.
Code coverage (see above) is a good way to find dead code in your app. Code coverage (see above) is a good way to find dead code in your app.
@ -163,7 +198,7 @@ booleans are never `null` when performing arithmetic, and that your program
does not run into range error when operating on lists, letting the compiler does not run into range error when operating on lists, letting the compiler
remove some of the error checking code. remove some of the error checking code.
These options are specified in `pubspec.yaml`. Specify these options in `pubspec.yaml`.
Example: Example:
@ -196,35 +231,36 @@ Change detection profiler repeatedly performs change detection without invoking
any user actions, such as clicking buttons or entering text in input fields. It any user actions, such as clicking buttons or entering text in input fields. It
then computes the average amount of time it took to perform a single cycle of then computes the average amount of time it took to perform a single cycle of
change detection in milliseconds and prints it to the console. This number change detection in milliseconds and prints it to the console. This number
depends on the current state of the UI. You will likely see different numbers depends on the current state of the UI. You are likely to see different numbers
as you go from one screen in your application to another. as you go from one screen in your application to another.
#### Running the profiler #### Running the profiler
Enable debug tools (see above), then in the dev console enter the following: Enable the debugging tools (see above),
then in the dev console enter the following:
```javascript ```javascript
ng.profiler.timeChangeDetection(); ng.profiler.timeChangeDetection();
``` ```
The results will be printed to the console. The results are printed to the console.
#### Recording CPU profile #### Recording CPU profiles
Pass `{record: true}` an argument: To record a profile, pass `{record: true}` to `timeChangeDetection()`:
```javascript ```javascript
ng.profiler.timeChangeDetection({record: true}); ng.profiler.timeChangeDetection({record: true});
``` ```
Then open the "Profiles" tab. You will see the recorded profile titled Then open the **Profiles** tab. The recorded profile has the title
"Change Detection". In Chrome, if you record the profile repeatedly, all the **Change Detection**. In Chrome, if you record the profile repeatedly, all the
profiles will be nested under "Change Detection". profiles are nested under Change Detection.
#### Interpreting the numbers #### Interpreting the numbers
In a properly-designed application repeated attempts to detect changes without In a properly designed application, repeated attempts to detect changes without
any user actions should result in no changes to be applied on the UI. It is any user actions result in no changes to the UI. It is
also desirable to have the cost of a user action be proportional to the amount also desirable to have the cost of a user action be proportional to the amount
of UI changes required. For example, popping up a menu with 5 items should be of UI changes required. For example, popping up a menu with 5 items should be
vastly faster than rendering a table of 500 rows and 10 columns. Therefore, vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
@ -248,24 +284,26 @@ Then look for hot spots using
#### Reducing change detection cost #### Reducing change detection cost
There are many reasons for slow change detection. To gain intuition about There are many reasons for slow change detection. To gain intuition about
possible causes it would help to understand how change detection works. Such a possible causes it helps to understand how change detection works. Such a
discussion is outside the scope of this document (TODO link to docs), but here discussion is outside the scope of this document,
are some key concepts in brief. but here are some key concepts.
By default Angular uses "dirty checking" mechanism for finding model changes. <!-- TODO: link to change detection docs -->
By default, Angular uses a _dirty checking_ mechanism to find model changes.
This mechanism involves evaluating every bound expression that's active on the This mechanism involves evaluating every bound expression that's active on the
UI. These usually include text interpolation via `{{expression}}` and property UI. These usually include text interpolation via `{{expression}}` and property
bindings via `[prop]="expression"`. If any of the evaluated expressions are bindings via `[prop]="expression"`. If any of the evaluated expressions are
costly to compute they could contribute to slow change detection. A good way to costly to compute, they might contribute to slow change detection. A good way to
speed things up is to use plain class fields in your expressions and avoid any speed things up is to use plain class fields in your expressions and avoid any
kinds of computation. Example: kind of computation. For example:
```dart ```dart
@View( @View(
template: '<button [enabled]="isEnabled">{{title}}</button>' template: '<button [enabled]="isEnabled">{{title}}</button>'
) )
class FancyButton { class FancyButton {
// GOOD: no computation, just return the value // GOOD: no computation, just returns the value
bool isEnabled; bool isEnabled;
// BAD: computes the final value upon request // BAD: computes the final value upon request
@ -274,11 +312,13 @@ class FancyButton {
} }
``` ```
Most cases like these could be solved by precomputing the value and storing the Most cases like these can be solved by precomputing the value and storing the
final value in a field. final value in a field.
Angular also supports a second type of change detection - the "push" model. In Angular also supports a second type of change detection: the _push_ model. In
this model Angular does not poll your component for changes. Instead, the this model, Angular does not poll your component for changes. Instead, the
component "tells" Angular when it changes and only then does Angular perform component tells Angular when it changes, and only then does Angular perform
the update. This model is suitable in situations when your data model uses the update. This model is suitable in situations when your data model uses
observable or immutable objects (also a discussion for another time). observable or immutable objects.
<!-- TODO: link to discussion of push model -->