- We need to extend the event object with such an instance so we access it .
- We also add a local template variable #rect to the SVG element, so that ViewChild(‘rect’) can query it .
- Rendering 10000 SVG boxes isn’t necessarily a hard nor realistic task it gets quite interesting when each of these boxes need to be draggable, because… well whenever there’s a mousemove event being fired, Angular has to perform change detection and rerender what needs to be rerendered.
- We’re dealing with 10000 draggable SVG boxes and all of them are checked on every change (every mousemove event).
- Special Tip : Learn in our article about Angular’s Change Detection why it’s performed on every mousemove event
In this article we discuss tips and tricks to make Angular blazingly fast!
Get a ticket →
Contents are based on Angular version >= 2.x unless explicitely stated differently.
Angular claims to be very fast by default. What does “fast” really mean? Of course, this always depends on the context. What does our application do? How many different things is it doing at a certain point? How is our application’s component tree structured and how many bindings does it introduce? This and other questions come into play when trying to figure out, how we can make our applications faster.
A couple of weeks ago, I had the honour to give a talk about Angular and React – Friends learning from each other at NG-BE together with Oliver Zeigermann, and we were discussing a demo application in which we compared the default performance and what we can do to make it faster. In this article we’d like to take this demo and show some tips and tricks to make it blazingly fast. One or the other trick might help speeding up your application as well.
event being fired, Angular has to perform change detection and rerender what needs to be rerendered. With 10000 boxes, this can be quite a lot of work.
Let’s not get too overwhelmed by the code. The only really important parts here are:
This one really just renders an SVG rect element using a couple of bindings to set the coordinates from the given box object.
Okay cool, so that’s our app. Let’s try it out and see how it performs. Simply run it and click and drag and drop a box.
By clicking and dragging a box, we can see and feel that the app is quite janky. Time to measure how fast it really is!
event has been fired, as this is the work Angular has to do when we drag and drop a box.
Try it out yourself, all you need to do is:
Ideally, any kind of measuring is done in an incognito browser tab so the recorded numbers won’t be affected by resources used by browser extensions or other browser tabs. Also, try to measure not only once but rather 3-5 times as the results will always vary a little bit. This helps us coming up with a decent average value.
Here are the numbers we measured on a MacBook Air (1,7 GHz Intel Core i7, 8 GB DDR3) in Chrome (Version 55.0.2883.95 (64-bit)):
events being fired when moving the mouse, that’s why we’re showing fastest and slowest numbers. Also, these numbers might look different on your local machine. Okay, so it takes Angular roughly ~42ms – ~55ms in average to render 10000 boxes. That’s not too bad, considering that this is completely unoptimized. However, we want to learn how to make it faster. Let’s take a look!
Again, Angular is very fast right out of the box. However, it turns out that there are a lot of things we can do to make our code even faster. The following are ideas for performance improvements we’ve came up with in collaboration with Angular’s core team member Tobias, who mainly works on the compiler and kind of knows how to make things fast.
change detection strategy enables us to reduce the number of checks Angular has to make when a change in our application happens.
’s input values are immutable.
To make all inputs immutable, we simply create new references every time we update a box:
That’s it! Here’s a the improved demo:
At this point it gets rather hard to notice an actual difference. This is because the previous unoptimized demo was already pretty fast. Let’s measure again and see if our application is faster (these profiles are made on the same machine as the previous ones).
does indeed improve our runtime performance. We may not notice a huge visual difference, but as we can see in the numbers, our application is now about as twice as fast. Considering the small change we needed to do, this is a great result!
It turns out, we could improve this even further. Right now, all 10000 boxes are checked, only the views are skipped – you know, the 39996 bindings. This is because in order to find out if an input has changed or not (to skip a component’s view), Angular needs to check the component. We could introduce some kind of segmentation model that divides the 10000 boxes into, let’s say ten, segments with 1000 boxes each. This would reduce the number of components to be checked to just 999.
However, this would not only make our code way more complicated, it also changes the application algorithm, which is what we’re trying to avoid in the first place.
’s source code, we can see that it not only creates DOM items it iterates through, it also keeps track of the position of each item, in case things have been moved around. This is great for animations as we can animate-in and -out naturally.
in another article. However, we put the source code in the following demo, feel free to check it out:
, it’s probably not worth it if we only save ~5ms in average.
’s of each component, with which we can enable or disable change detection entirely. We touched on that in our article on change detection in Angular as well, but let’s discuss how this is useful in our demo application.
doesn’t prevent Angular from checking the boxes themselves, only their views. However, what if we could turn off change detection entirely for all components and only perform change detection for the box component that is actually being moved? This would obviously result in way less work per task as we aren’t checking 10000 boxes anymore, but only one.
life cycle hook.
Here’s what that looks like:
We do exactly the same for the all box components.
Okay cool, now we should see all the boxes but the dragging and dropping doesn’t work anymore. That makes sense because change detection is turned off entirely and no handlers for any events are executed anymore.
which performs change detection just like this:
object with such an instance so we access it accordingly.
event like this:
can query it accordingly.
in all other methods where needed.
Here’s the demo application in action, updating only the box that is being dragged:
Angular is very fast by default and still, it gives us tools to fine tune the performance of our applications by handing over a lot of control over how change detection is performed. Is there anything else we can do? It turns out yes.
All demos have been executed in Angular’s dev mode. We can turn on production mode, which should increase performance a little bit further as it makes sure to run change detection only once, as opposed to twice in dev mode.
We should keep in mind though, that none of the shown tricks is a silver bullet. They may or may not work for your particular use case.
Hopefully you’ve learned one or the other thing about how to make your apps faster!