Before looking of the binding of Angular2+ Lets start look at the zone.js library because zone.js plays a major role in Angular Binding
Understanding Zone
Lets do a simple js program for calculating the total execution timing of set of function.
In the above example it shows the time exact time for the execution of three method. But there all the methods are synchronized lets try with by adding an asynchronous method
Here while printing the timing doSomething()
method execution time wont considered because it runs asynchronous way. asynchronous operations are added to the browser’s event queue, which eventually gets cleaned up by the event loop once there’s time for that.
This is exactly where zones come into play. Zones can perform an operation - such as starting or stopping a timer, or saving a stack trace - each time that code enters or exits a zone. They can override methods within our code, or even associate data with individual zones.
Once we’ve embedded zone.js into our website, we have access to the global zone object. zone comes with a method run() that takes a function which should be executed in that zone. In other words, if we’d like to run our code in a zone, we can already do it likes this:
In order to set up these hooks, we need to fork the current zone. Forking a zone returns a new zone, which basically inherits from the “parent” zone. However, forking a zone also allows us to extend the returning zone’s behavior. We can fork a zone by calling .fork()
on the zone object.
Hooks are defined using a ZoneSpecification
that we can pass to fork()
. We can take advantage of the following hooks:
onZoneCreated - Runs when zone is forked
beforeTask - Runs before a function called with zone.run is executed
afterTask - Runs after a function in the zone runs
onError - Runs when a function passed to zone.run will throw
Monkey-patched Hooks in Zone
Monkey patching is a technique to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.
It turns out that there are a few other hooks. In fact, those aren’t just hooks, but monkey-patched methods on the global scope. As soon as we embed zone.js in our site, pretty much all methods that cause asynchronous operations are monkey-patched to run in a new zone.
For example, when we call setTimeout()
we actually call Zone.setTimeout()
, which in turn creates a new zone using zone.fork()
in which the given handler is executed. And that’s why our hooks are executed as well, because the forked zone in which the handler will be executed, simply inherits from the parent zone.
There are some other methods that zone.js overrides by default and provides us as hooks:
Zone.setInterval()
Zone.alert()
Zone.prompt()
Zone.requestAnimationFrame()
Zone.addEventListener()
Zone.removeEventListener()
Zones with Angular
In Angular 2+ the bindings are fully dependent on zone
Let’s do an experiment. Go and take your favorite Angular 2 app, and don’t include zone.js. See what happens, I’ll wait here. Notice anything interesting? None of the bindings are working!
Based on the Angular Concept, Application state change is caused by three things:
Events - User events like click, change, input, submit, …
XMLHttpRequests - E.g. when fetching data from a remote service
Timers - setTimeout(), setInterval(), because JavaScript
Zones monkey-patches global asynchronous operations such as setTimeout() and addEventListener(), which is why Angular can easily find out, when to update the DOM.
NgZone in Angular
NgZone is basically a forked zone that extends its API and adds some additional functionality to its execution context. One of the things it adds to the API is the following set of custom events we can subscribe to, as they are observable streams:
onTurnStart() - Notifies subscribers just before Angular’s event turn starts. Emits an event once per browser task that is handled by Angular. onTurnDone() - Notifies subscribers immediately after Angular’s zone is done processing the current turn and any micro tasks scheduled from that turn. onEventDone() - Notifies subscribers immediately after the final onTurnDone() callback before ending VM event. Useful for testing to validate application state.
The main reason Angular adds its own event emitters instead of relying on beforeTask and afterTask callbacks, is that it has to keep track of timers and other micro tasks. It’s also nice that Observables are used as an API to handle these events
Running code outside Angular’s zone
Suppose we have a case that perform an event on every mouse move. We probably don’t want to perform change detection every time mousemove is fired as it would slow down our application and results in very bad user experience. That’s why NgZone comes with an API runOutsideAngular()
which performs a given task in NgZone’s parent zone, which does not emit an onTurnDone event, hence no change detection is performed.
To demonstrate this useful feature, let’s take look at the following code:
increaseProgress()
calls itself every 10 milliseconds until progress equals 100. Once it’s done, the given doneCallback will execute. Notice how we use setTimeout()
to increase the progress.
Running this code in the browser, basically demonstrates what we already know. After each setTimeout()
call, Angular performs change detection and updates the view, which allows us to see how progress is increased every 10 milliseconds. It gets more interesting when we run this code outside Angular’s zone. Let’s add a method that does exactly that.
No comments:
Post a Comment