Optimize Angular’s Change Detection

Share this video with your friends

Social Share Links

Send Tweet

Change Detection the magic behind Angular that automatically recognizes when changes happen. That’s either due to manual triggering or through asynchronous events. Once a change is detected, it iterates through the various Angular Components and triggers a refresh. Usually it is very fast, however - especially in larger apps - it might trigger lots of computations and thus block the main browser thread. In this lesson we’re going to learn how to optimize Angular’s change detection mechanism by reducing the amount of components it needs to update and via pure pipes.

Juri Strumpflohner: [0:00] Here, we have a simulated business application, which is two different kind of lists of employees, one which belongs to the department of sales, and one that belongs to the R&D department.

[0:11] Now, if I click in here, I write something, I hit enter, you can already see that the application is quite lagging. We'll get here a name and enter. I can jump over here, do the same, but you see that there is a huge delay on what I type in actually when it gets rendered.

[0:29] We want to optimize that kind of application. Let's see how it's actually structured. Let me make this a bit smaller again.

[0:36] What we've seen here are these two adjacent lists. These are both coming from the app-employee-list. They are just getting feed with different kind of data.

[0:45] Now, if we go inside here, we see that we have here our app-employee-list which renders the data that comes in via here @input.

[0:53] For each item in the row, it calculates here that number based on the input it gets. We see here that calculate function.

[1:00] That calculate function resides here in our component which makes here a so-called simulated business procedure, a business calculation which is quite costly in this case. It calculates the Fibonacci number.

[1:12] One thing we can optimize in Angular applications often is to change it to cycles Angular has to perform. Generally speaking, it is quite fast, but in certain cases, we can give it some help. Let's take a look at our component tree. What we have here is that app-root, which is the very top.

[1:28] Then we have that employee-list which is the one from sales and employee-list from R&D and here our app-root in-between. This is a tree structure. Both of these employee lists below have different kind of rows below. We have here the employee-list for sales as well as the employee-list for R&D.

[1:48] Whenever we insert something here, and our employees for the sales part, what happens is that at our top here, the Change Detection cycle kicks in because it has detected some changes.

[1:58] It will go down on both, the employee-list for sales as well as on the employee-list for R&D and recompute every row, which means recompute Fibonacci for every entry here in those lists, in both of them.

[2:10] Already, in this case, we could optimize by telling Angular, "Look, we just changed here something on that side, so you can avoid doing changes for the whole part of the employee-list in the R&D section." Let's close this and see how we can do that. In our app-employee-list, we can go down in our component to finishing.

[2:29] There's a property called changeDetection which you can set to the ChangeDetectionStrategy.OnPush. OnPush will now trigger changeDetection only if the reference of the data passed through writer inputs has actually changed, so we got a new list of data.

[2:46] This obviously happens here for the sales department once we type in here a new person, but it doesn't happen for the R&D part. Let's see whether our performance increased here. Let's type in here. You see the animation's already faster. We already get a better performance, but there's still some lag in application.

[3:05] Let's see how we can further improve it. Another point we can improve is this calculate here. This happens for every entry in the list every time we change that list. This is something we can actually avoid.

[3:18] We know if you go to that calculate function, that whenever we call Fibonacci with a certain number, with the same number, we will always get the same result. We actually can avoid doing the recomputations every time. That's because Fibonacci's a pure function. What we can do is to use Angular's pure pipes to have us improve here the performance.

[3:40] Let's generate here a new Angular pipe. We do that with ng command with a generate operation we call pipe. We placed in it employee-list, and we call it calculate. For now, we skip the tests and create a new calculate pipe here in, and it also inserts it properly in the employee-list module.

[3:59] Let's go and have a look here at our pipe implementation. Notice we factor our employee-list and move over that logic. First of all, we can move over that Fibonacci calculation, which will happen here. We get here a number which is a number we pass ahead to the Fibonacci calculation.

[4:19] Here, we just returned a result of that Fibonacci. Obviously, we also need to move over the Fibonacci function, which we can just here cut out. Let's also here remove that function, which is no more needed. Let's move that over. We're at top here. Here our pipe's actually done.

[4:40] Angular pipes are pure by default. We can change that via that setting here, which is called pure inside it to force in case we have a non-pure pipe. Pure means that whenever the same input comes inside here, that value is not calculated anymore because Angular knows it has seen it already before and just returns the result.

[4:58] Let's save this for now. We can now go over to our employee-list which we need to refactor because that calculate function doesn't exist anymore, so we can remove here this. We can now use our new calculate pipe. Let's save again. Let's here make our window a little bit bigger.

[5:19] Let's type in. You can see how fast the typing now works. I can type in new values, and it's really speedingly fast. We have actually taken two measures. First of all, the changeDetection, which we changed to OnPush. Then we introduced a pure pipe to optimize our computation, which happens inside our lists.