106 lines
3.2 KiB
Markdown
106 lines
3.2 KiB
Markdown
|
# 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.
|