angular-cn/modules/angular2/docs/core/12_zones.md

106 lines
3.2 KiB
Markdown
Raw Normal View History

# Zones
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for
JavaScript. Zones are used to intercept all async operation callbacks in the browser. By intercepting async
callbacks angular can automatically execute the change detection at the end of the VM turn to update the application
UI bindings. Zones means that in Angular v2 you don't have to remember to call `rootScope.$apply()` in your async call.
## Execution Context
```
zone['inTheZone'] = false;
zone.run(function () {
zone['inTheZone'] = true;
setTimeout(function () {
console.log('async in the zone: ' + zone['inTheZone']);
}, 0);
});
console.log('sync in the zone: ' + zone['inTheZone']);
```
The above will log:
```
sync in the zone: false
async in the zone: true
```
In the above example the `zone` is a global-callback-local variable. To the `zone` we can attach arbitrary properties
such as `inTheZone`. When we enter the zone, we get a new `zone` context (which inherits all properties from the
parent zone), once we leave the zone, the previous `zone` variable is restored. The key part is that when a async
callback is scheduled in the zone, as is the case with `setTimeout`, the current `zone` variable is captured and
restored on the callback. This is why the output of the `inTheZone` property inside the callback of the `setTimeout`
prints `true`.
## Callback Interception
In addition to storing properties on the current `zone`, zones can also allow us to intercept all async callbacks
and notify us before and after the callback executes.
```
zone.fork({
afterTask: function () {
// do some cleanup
}
}).run(function () {
// do stuff
});
```
The above example will execute the `afterTask` function not only after the `run` finishes, but also after any callback
execution which was registered in the `run` block.
## Putting it all together in Angular
In Angular2 it is not necessary to notify Angular of changes manually after async callback, because angular relevant
async callbacks are intercepted. The question is how do we know which callbacks are angular relevant?
```
/// Some other code running on page can do async operation
document.addEventListener('mousemove', function () {
console.log('Mouse moved.');
});
var AngularZone = {
afterTask: function () {
console.log('ANGULAR AUTO-DIGEST!');
}
};
var ngZone = zone.fork(AngularZone);
ngZone.run(function() {
console.log('I aware of angular, I should cause digest.');
document.addEventListener('click', function () {
console.log('Mouse clicked.');
});
});
```
Will produce:
```
I aware of angular, I should cause digest.
ANGULAR AUTO-DIGEST!
```
Moving the mouse will produce many:
```
Mouse moved.
```
But clicking will produce:
```
Mouse clicked.
ANGULAR AUTO-DIGEST!
```
Notice how the place where the listener was register will effect weather or not angular will be notified of the
async call and cause a change detection to run to update the UI.
Being able to globally intercept the async operation is important to have a seamless integration with all existing
libraries. But it is equally important to be able to differentiate between Angular and none Angular code running
on the same page concurrently.