Using Zones in Angular for better performance by thoughtram
- That’s why Jordi Collell pointed out that another option would be to take advantage of Zone APIs, to execute our code outside the Angular zone, which will prevent Angular from running unnecessary change detection tasks.
- We’ll take a look at some numbers later, but let’s quickly recap Zones and then dive into the code and discuss how Jordi used Angular’s APIs to achieve this performance first.
- We’re working with the DOM element instead of a box object with bindings for and , because bindings won’t be change detected since we’re running the code outside Angular’s Zone.
- The cool thing about is not only that it allows us to run code outside Angular’s Zone, it also comes with APIs to run code inside the Angular Zone, which ultimately will cause Angular to perform change detection again.
- Using Zones is a great way to escape Angular’s change detection, without detaching change detectors and making the application code too complex.
In this article we’ll take a look at how to use Zone APIs to improve our app’s performance!
Get a ticket →
Contents are based on Angular version >= 2.x unless explicitely stated differently.
APIs as well as tricks on how to detach change detectors and many more. While we were covering many different options to improve the demo application’s performance, we certainly haven’t talked about all possible options.
That’s why Jordi Collell pointed out that another option would be to take advantage of Zone APIs, to execute our code outside the Angular zone, which will prevent Angular from running unnecessary change detection tasks. He even put time and energy into creating a demo plunk that shows how to do exactly that.
We want to say thank you for his contribution and think that the solution he came up with deserves its own article. So in this article we’re going to explore his plunk and explain how Jordi used Zones to make our demo application perform at almost 60 fps.
Before we jump right into the code, let’s first take a look at the demo plunk with the running application. As a quick recap: The idea was to render 10.000 draggable SVG boxes. Rendering 10.000 boxes is not a super sophisticated task, however, the challenge lies in making the dragging experience as smooth as possible. In other words, we aim for 60 fps (frames per second), which can be indeed challenging, considering that Angular re-renders all 10.000 boxes by default when an even has fired (that we bound to).
Here’s the demo with the unoptimized version:
APIs to achieve this performance first.
, we need to get an understanding of what Zones actually are and how they are useful in the Angular world. We won’t go into too much detail here as we’ve already written two articles on this topic:
, … etc.
service to fetch data from a remote server. The following snippet shows how such a call can change application state:
The nice thing about this is that we as developers don’t have to care about notifying Angular to perform change detection, because Zones will do it for us as Angular subscribes to them under the hood.
Okay, now that we touched on that, let’s take a look at how they can be used to make our demo app fast.
Three (3) event handlers are bound to the outer SVG element. When any of these events fire and their handlers have been executed then change detection is performed. In fact, this means that Angular will run change detection, even when we just move with the mouse over the boxes without actually dragging a single box!
enables us to explicitly run certain code outside Angular’s Zone, preventing Angular to run any change detection. So basically, handlers will still be executed, but since they won’t run inside Angular’s Zone, Angular won’t get notified that a task is done and therefore no change detection will be performed. We only want to run change detection once we release the box we are dragging.
event handler to imperatively add that event listener to the document.
Here’s what that looks like:
, because bindings won’t be change detected since we’re running the code outside Angular’s Zone. In other words, we do update the DOM, so we can see the box is moving, but we aren’t actually updating the box model (yet).
handler. However, it won’t add any value performance-wise, so we decided to keep it in the template for simplicity-sake:
and give it the code that should be executed.
event on every mouseUp. Otherwise, the event handler would still be executed on every mouse move. In other words the box would keep moving even after the finger was lifted, essentially taking the drop part out of drag and drop. In addition to that, we would pile up event handlers, which could not only cause weird side effects but also blows up our runtime memory.
Alright, now that we know how Jordi implemented this version of our demo application, let’s take a look at some numbers! The following numbers have been recorded using the exact same techniques on the exact same machine as in our previous article on performance.
’s APIs to run code outside or inside Angular. Based on the numbers, we can even say that this version is about as fast as the fastest solution we came up with in our previous article. Considering that the developer experience is much better when using Zones APIs, since they are easier to use than manually detaching and re-attaching change detector references, it’s definitely the most “beautiful” performance improvement we have so far.
object, which is something we should always try to avoid. If we wanted to use this code with on the server-side then direct access of the window variable would be problematic. We will discus these server-side specific issues in a future article. For the sake of this demo, this isn’t a big deal though.
Again, a huge shout-out goes to Jordi Collell who not only made us adding this option, but also taking the time to actually implement a first version of this demo!