parent
4d458db1b5
commit
a5eb0e56b6
|
@ -47,7 +47,7 @@ To clarify how changes are detected and values updated, consider the following c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// example 1: update data inside button click event handler
|
// Example 1: update data inside button click event handler
|
||||||
document.getElementById('btn').addEventListener('click', () => {
|
document.getElementById('btn').addEventListener('click', () => {
|
||||||
// update value
|
// update value
|
||||||
value = 'button update value';
|
value = 'button update value';
|
||||||
|
@ -55,7 +55,7 @@ To clarify how changes are detected and values updated, consider the following c
|
||||||
detectChange();
|
detectChange();
|
||||||
});
|
});
|
||||||
|
|
||||||
// example 2: Http Request
|
// Example 2: HTTP Request
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.addEventListener('load', function() {
|
xhr.addEventListener('load', function() {
|
||||||
// get response from server
|
// get response from server
|
||||||
|
@ -66,7 +66,7 @@ To clarify how changes are detected and values updated, consider the following c
|
||||||
xhr.open('GET', serverUrl);
|
xhr.open('GET', serverUrl);
|
||||||
xhr.send();
|
xhr.send();
|
||||||
|
|
||||||
// example 3: setTimeout
|
// Example 3: setTimeout
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// update value inside setTimeout callback
|
// update value inside setTimeout callback
|
||||||
value = 'timeout update value';
|
value = 'timeout update value';
|
||||||
|
@ -74,18 +74,18 @@ To clarify how changes are detected and values updated, consider the following c
|
||||||
detectChange();
|
detectChange();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
// example 4: Promise.then
|
// Example 4: Promise.then
|
||||||
Promise.resolve('promise resolved a value').then((v) => {
|
Promise.resolve('promise resolved a value').then(v => {
|
||||||
// update value inside Promise thenCallback
|
// update value inside Promise thenCallback
|
||||||
value = v;
|
value = v;
|
||||||
// call detectChange manually
|
// call detectChange manually
|
||||||
detectChange();
|
detectChange();
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
// example 5: some other asynchronous APIs
|
// Example 5: some other asynchronous APIs
|
||||||
document.getElementById('canvas').toBlob(blob => {
|
document.getElementById('canvas').toBlob(blob => {
|
||||||
// update value when blob data is created from the canvas
|
// update value when blob data is created from the canvas
|
||||||
value = `value updated by canvas, size is ${blog.size}`;
|
value = `value updated by canvas, size is ${blob.size}`;
|
||||||
// call detectChange manually
|
// call detectChange manually
|
||||||
detectChange();
|
detectChange();
|
||||||
});
|
});
|
||||||
|
@ -108,7 +108,7 @@ To understand how change detection works, first consider when the application ne
|
||||||
|
|
||||||
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" header="src/app/click-me.component.ts"></code-example>
|
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" header="src/app/click-me.component.ts"></code-example>
|
||||||
|
|
||||||
3. Http Data Request. You can also get data from a server through an Http request. For example:
|
3. HTTP Data Request. You can also get data from a server through an HTTP request. For example:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -129,7 +129,7 @@ export class AppComponent implements OnInit {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
4. MacroTasks, such as `setTimeout()`/`setInterval()`. You can also update the data in the callback function of `macroTask` such as `setTimeout()`. For example:
|
4. MacroTasks, such as `setTimeout()` or `setInterval()`. You can also update the data in the callback function of a `macroTask` such as `setTimeout()`. For example:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -148,7 +148,7 @@ export class AppComponent implements OnInit {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
5. MicroTask, such as `Promise.then()`. Other asynchronous APIs return a Promise object (such as `fetch`), so the `then()` callback function can also update the data. For example:
|
5. MicroTasks, such as `Promise.then()`. Other asynchronous APIs return a Promise object (such as `fetch`), so the `then()` callback function can also update the data. For example:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -167,27 +167,23 @@ export class AppComponent implements OnInit {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Other async operations. In addition to `addEventListener()`/`setTimeout()`/`Promise.then()`, there are other operations that can update the data asynchronously. Some examples include `WebSocket.onmessage()` and `Canvas.toBlob()`.
|
6. Other async operations. In addition to `addEventListener()`, `setTimeout()` and `Promise.then()`, there are other operations that can update the data asynchronously. Some examples include `WebSocket.onmessage()` and `Canvas.toBlob()`.
|
||||||
|
|
||||||
The preceding list contains most common scenarios in which the application might change the data. Angular runs change detection whenever it detects that data could have changed.
|
The preceding list contains most common scenarios in which the application might change the data. Angular runs change detection whenever it detects that data could have changed.
|
||||||
The result of change detection is that DOM is updated with new data. Angular detects the changes in different ways. For component initialization, Angular calls change detection explicitly. For [asynchronous operations](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous), Angular uses a Zone to detect changes in places where the data could have possibly mutated and it runs change detection automatically.
|
The result of change detection is that the DOM is updated with new data. Angular detects the changes in different ways. For component initialization, Angular calls change detection explicitly. For [asynchronous operations](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous), Angular uses a zone to detect changes in places where the data could have possibly mutated and it runs change detection automatically.
|
||||||
|
|
||||||
|
|
||||||
## Zones and execution contexts
|
## Zones and execution contexts
|
||||||
|
|
||||||
A zone provides an execution context that persists across async tasks. [Execution Context](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) is an abstract concept that holds information about the environment within the current code being executed. Consider the following example.
|
A zone provides an execution context that persists across async tasks. [Execution Context](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) is an abstract concept that holds information about the environment within the current code being executed. Consider the following example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const callback = function() {
|
const callback = function() {
|
||||||
console.log('setTimeout callback context is', this);
|
console.log('setTimeout callback context is', this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctx1 = {
|
const ctx1 = { name: 'ctx1' };
|
||||||
name: 'ctx1'
|
const ctx2 = { name: 'ctx2' };
|
||||||
};
|
|
||||||
const ctx2 = {
|
|
||||||
name: 'ctx2'
|
|
||||||
};
|
|
||||||
|
|
||||||
const func = function() {
|
const func = function() {
|
||||||
console.log('caller context is', this);
|
console.log('caller context is', this);
|
||||||
|
@ -198,8 +194,8 @@ func.apply(ctx1);
|
||||||
func.apply(ctx2);
|
func.apply(ctx2);
|
||||||
```
|
```
|
||||||
|
|
||||||
The value of `this` in the callback of `setTimeout` might differ depending on when `setTimeout` is called.
|
The value of `this` in the callback of `setTimeout()` might differ depending on when `setTimeout()` is called.
|
||||||
Thus you can lose the context in asynchronous operations.
|
Thus, you can lose the context in asynchronous operations.
|
||||||
|
|
||||||
A zone provides a new zone context other than `this`, the zone context that persists across asynchronous operations.
|
A zone provides a new zone context other than `this`, the zone context that persists across asynchronous operations.
|
||||||
In the following example, the new zone context is called `zoneThis`.
|
In the following example, the new zone context is called `zoneThis`.
|
||||||
|
@ -227,19 +223,19 @@ Zone.js can create contexts that persist across asynchronous operations as well
|
||||||
const zone = Zone.current.fork({
|
const zone = Zone.current.fork({
|
||||||
name: 'zone',
|
name: 'zone',
|
||||||
onScheduleTask: function(delegate, curr, target, task) {
|
onScheduleTask: function(delegate, curr, target, task) {
|
||||||
console.log('new task is scheduled: ', task.type, task.source);
|
console.log('new task is scheduled:', task.type, task.source);
|
||||||
return delegate.scheduleTask(target, task);
|
return delegate.scheduleTask(target, task);
|
||||||
},
|
},
|
||||||
onInvokeTask: function(delegate, curr, target, task, applyThis, applyArgs) {
|
onInvokeTask: function(delegate, curr, target, task, applyThis, applyArgs) {
|
||||||
console.log('task will be invoked', task.type, task.source);
|
console.log('task will be invoked:', task.type, task.source);
|
||||||
return delegate.invokeTask(target, task, applyThis, applyArgs);
|
return delegate.invokeTask(target, task, applyThis, applyArgs);
|
||||||
},
|
},
|
||||||
onHasTask: function(delegate, curr, target, hasTaskState) {
|
onHasTask: function(delegate, curr, target, hasTaskState) {
|
||||||
console.log('task state changed in the zone', hasTaskState);
|
console.log('task state changed in the zone:', hasTaskState);
|
||||||
return delegate.hasTask(target, hasTaskState);
|
return delegate.hasTask(target, hasTaskState);
|
||||||
},
|
},
|
||||||
onInvoke: function(delegate, curr, target, callback, applyThis, applyArgs) {
|
onInvoke: function(delegate, curr, target, callback, applyThis, applyArgs) {
|
||||||
console.log('the callback will be invoked', callback);
|
console.log('the callback will be invoked:', callback);
|
||||||
return delegate.invoke(target, callback, applyThis, applyArgs);
|
return delegate.invoke(target, callback, applyThis, applyArgs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -252,43 +248,43 @@ zone.run(() => {
|
||||||
|
|
||||||
The above example creates a zone with several hooks.
|
The above example creates a zone with several hooks.
|
||||||
|
|
||||||
`onXXXTask` hooks trigger when the status of Task changes.
|
The `onXXXTask` hooks trigger when the status of the task changes.
|
||||||
The Zone Task concept is very similar to the Javascript VM Task concept.
|
The concept of a *Zone Task* is very similar to the JavaScript VM Task concept:
|
||||||
- `macroTask`: such as `setTimeout()`.
|
- `macroTask`: such as `setTimeout()`
|
||||||
- `microTask`: such as `Promise.then()`.
|
- `microTask`: such as `Promise.then()`
|
||||||
- `eventTask`: such as `element.addEventListener()`.
|
- `eventTask`: such as `element.addEventListener()`
|
||||||
|
|
||||||
These hooks trigger under the following circumstances:
|
These hooks trigger under the following circumstances:
|
||||||
|
|
||||||
- `onScheduleTask`: triggers when a new asynchronous task is scheduled, such as when you call `setTimeout()`.
|
- `onScheduleTask`: triggers when a new asynchronous task is scheduled, such as when you call `setTimeout()`.
|
||||||
- `onInvokeTask`: triggers when an asynchronous task is about to execute, such as when the callback of `setTimeout()` is about to execute.
|
- `onInvokeTask`: triggers when an asynchronous task is about to execute, such as when the callback of `setTimeout()` is about to execute.
|
||||||
- `onHasTask`: triggers when the status of one kind of task inside a zone changes from stable to unstable or from unstable to stable. A status of stable means there are no tasks inside the Zone, while unstable means a new task is scheduled in the zone.
|
- `onHasTask`: triggers when the status of one kind of task inside a zone changes from stable to unstable or from unstable to stable. A status of "stable" means there are no tasks inside the zone, while "unstable" means a new task is scheduled in the zone.
|
||||||
- `onInvoke`: triggers when a synchronous function is going to execute in the zone.
|
- `onInvoke`: triggers when a synchronous function is going to execute in the zone.
|
||||||
|
|
||||||
With these hooks, `Zone` can monitor the status of all synchronous and asynchronous operations inside a zone.
|
With these hooks, `Zone` can monitor the status of all synchronous and asynchronous operations inside a zone.
|
||||||
|
|
||||||
The above example returns the following output.
|
The above example returns the following output:
|
||||||
|
|
||||||
```
|
```
|
||||||
the callback will be invoked () => {
|
the callback will be invoked: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('timeout callback is invoked.');
|
console.log('timeout callback is invoked.');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
new task is scheduled: macroTask setTimeout
|
new task is scheduled: macroTask setTimeout
|
||||||
task state changed in the zone { microTask: false,
|
task state changed in the zone: { microTask: false,
|
||||||
macroTask: true,
|
macroTask: true,
|
||||||
eventTask: false,
|
eventTask: false,
|
||||||
change: 'macroTask' }
|
change: 'macroTask' }
|
||||||
task will be invoked macroTask setTimeout
|
task will be invoked macroTask: setTimeout
|
||||||
timeout callback is invoked.
|
timeout callback is invoked.
|
||||||
task state changed in the zone { microTask: false,
|
task state changed in the zone: { microTask: false,
|
||||||
macroTask: false,
|
macroTask: false,
|
||||||
eventTask: false,
|
eventTask: false,
|
||||||
change: 'macroTask' }
|
change: 'macroTask' }
|
||||||
```
|
```
|
||||||
|
|
||||||
All of the functions of Zone are provided by a library called [zone.js](https://github.com/angular/angular/tree/master/packages/zone.js/README.md).
|
All of the functions of `Zone` are provided by a library called [Zone.js](https://github.com/angular/angular/tree/master/packages/zone.js/README.md).
|
||||||
This library implements those features by intercepting asynchronous APIs through monkey patching.
|
This library implements those features by intercepting asynchronous APIs through monkey patching.
|
||||||
Monkey patching is a technique to add or modify the default behavior of a function at runtime without changing the source code.
|
Monkey patching is a technique to add or modify the default behavior of a function at runtime without changing the source code.
|
||||||
|
|
||||||
|
@ -300,14 +296,14 @@ This service creates a zone named `angular` to automatically trigger change dete
|
||||||
1. When a sync or async function is executed.
|
1. When a sync or async function is executed.
|
||||||
1. When there is no `microTask` scheduled.
|
1. When there is no `microTask` scheduled.
|
||||||
|
|
||||||
### NgZone `run()`/`runOutsideOfAngular()`
|
### NgZone `run()` and `runOutsideOfAngular()`
|
||||||
|
|
||||||
`Zone` handles most asynchronous APIs such as `setTimeout()`, `Promise.then()`, and `addEventListener()`.
|
`Zone` handles most asynchronous APIs such as `setTimeout()`, `Promise.then()`, and `addEventListener()`.
|
||||||
For the full list, see the [Zone Module document](https://github.com/angular/angular/blob/master/packages/zone.js/MODULE.md).
|
For the full list, see the [Zone Module document](https://github.com/angular/angular/blob/master/packages/zone.js/MODULE.md).
|
||||||
Therefore in those asynchronous APIs, you don't need to trigger change detection manually.
|
Therefore in those asynchronous APIs, you don't need to trigger change detection manually.
|
||||||
|
|
||||||
There are still some third party APIs that Zone does not handle.
|
There are still some third party APIs that Zone does not handle.
|
||||||
In those cases, the NgZone service provides a [`run()`](api/core/NgZone#run) method that allows you to execute a function inside the angular zone.
|
In those cases, the `NgZone` service provides a [`run()`](api/core/NgZone#run) method that allows you to execute a function inside the angular zone.
|
||||||
This function, and all asynchronous operations in that function, trigger change detection automatically at the correct time.
|
This function, and all asynchronous operations in that function, trigger change detection automatically at the correct time.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -328,7 +324,7 @@ export class AppComponent implements OnInit {
|
||||||
|
|
||||||
By default, all asynchronous operations are inside the angular zone, which triggers change detection automatically.
|
By default, all asynchronous operations are inside the angular zone, which triggers change detection automatically.
|
||||||
Another common case is when you don't want to trigger change detection.
|
Another common case is when you don't want to trigger change detection.
|
||||||
In that situation, you can use another NgZone method: [runOutsideAngular()](api/core/NgZone#runoutsideangular).
|
In that situation, you can use another `NgZone` method: [`runOutsideAngular()`](api/core/NgZone#runoutsideangular).
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
|
@ -349,7 +345,7 @@ export class AppComponent implements OnInit {
|
||||||
|
|
||||||
### Setting up Zone.js
|
### Setting up Zone.js
|
||||||
|
|
||||||
To make Zone.js available in Angular, you need to import the zone.js package.
|
To make Zone.js available in Angular, you need to import the `zone.js` package.
|
||||||
If you are using the Angular CLI, this step is done automatically, and you will see the following line in the `src/polyfills.ts`:
|
If you are using the Angular CLI, this step is done automatically, and you will see the following line in the `src/polyfills.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
@ -364,17 +360,20 @@ Before importing the `zone.js` package, you can set the following configuration
|
||||||
- You can disable some asynchronous API monkey patching for better performance.
|
- You can disable some asynchronous API monkey patching for better performance.
|
||||||
For example, you can disable the `requestAnimationFrame()` monkey patch, so the callback of `requestAnimationFrame()` will not trigger change detection.
|
For example, you can disable the `requestAnimationFrame()` monkey patch, so the callback of `requestAnimationFrame()` will not trigger change detection.
|
||||||
This is useful if, in your application, the callback of the `requestAnimationFrame()` will not update any data.
|
This is useful if, in your application, the callback of the `requestAnimationFrame()` will not update any data.
|
||||||
- You can specify that certain DOM events not run inside the angular zone; for example, to prevent a `mousemove` or `scroll` event to trigger change detection.
|
- You can specify that certain DOM events do not run inside the angular zone; for example, to prevent a `mousemove` or `scroll` event to trigger change detection.
|
||||||
|
|
||||||
There are several other settings you can change.
|
There are several other settings you can change.
|
||||||
To make these changes, you need to create a `zone-flags.ts` file, such as the following.
|
To make these changes, you need to create a `zone-flags.ts` file, such as the following.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
(window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
// disable patching requestAnimationFrame
|
||||||
(window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
(window as any).__Zone_disable_requestAnimationFrame = true;
|
||||||
|
|
||||||
|
// disable patching specified eventNames
|
||||||
|
(window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove'];
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, import `zone-flags` before you import `zone` in the `polyfills.ts`.
|
Next, import `zone-flags` before you import `zone.js` in the `polyfills.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
|
@ -384,12 +383,12 @@ import `./zone-flags`;
|
||||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information of what you can configure, see the [zone.js](https://github.com/angular/angular/tree/master/packages/zone.js) documentation.
|
For more information about what you can configure, see the [Zone.js](https://github.com/angular/angular/tree/master/packages/zone.js) documentation.
|
||||||
|
|
||||||
### NoopZone
|
### NoopZone
|
||||||
|
|
||||||
`Zone` helps Angular know when to trigger change detection and let the developers focus on the application development.
|
`Zone` helps Angular know when to trigger change detection and let the developers focus on the application development.
|
||||||
By default, `Zone` is loaded and works without additional configuration. However, you don't have to use `Zone` to make Angular work, instead opting to trigger change detection on your own.
|
By default, `Zone` is loaded and works without additional configuration. However, you don't necessarily have to use `Zone` to make Angular work. Instead, you can opt to trigger change detection on your own.
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<div class="alert is-helpful">
|
||||||
|
|
||||||
|
@ -399,9 +398,9 @@ By default, `Zone` is loaded and works without additional configuration. However
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
To remove `zone.js`, make the following changes.
|
To remove Zone.js, make the following changes.
|
||||||
|
|
||||||
1. Remove the `zone.js` import from `polyfills.ts`.
|
1. Remove the `zone.js` import from `polyfills.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
|
@ -410,9 +409,9 @@ To remove `zone.js`, make the following changes.
|
||||||
// import 'zone.js/dist/zone'; // Included with Angular CLI.
|
// import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Bootstrap Angular with `noop zone` in `src/main.ts`.
|
2. Bootstrap Angular with the `noop` zone in `src/main.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'})
|
platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' })
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue