docs: copyedit DART_TOOLS.md
This commit is contained in:
parent
4d4d20edb9
commit
4087e3115b
160
TOOLS_DART.md
160
TOOLS_DART.md
|
@ -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 -->
|
||||||
|
|
Loading…
Reference in New Issue