In this video Iftach Bar explains how the digest loop works by adding an empty watcher and showing when it is being called.
- [Instructor] Understanding how to use dollar watch is just part of understanding how (mumbles) works. When we code dollar watch, we're provided with two functions as arguments. A watcher and a listener. The watcher function gets called from time to time and whenever it is called its return value is being compared with a return value from the last time the watcher function was run. If the two values are not equal, the listener function is called, the missing part of the puzzle is who performs this algorithm and when? The answer is the digest loop.
There is another function under scope called dollar apply. This function, initiates a dollar loop that will make all watchers run. Before we look at an example, I'm going to remove a lot of code I wrote previously regarding the internal controller. I'm going to remove all the implementation of the internal controller from (mumbles) and I'm going to remove it from the (mumbles) as well. Now that we're left with only playground controller and the simpler code, we can start playing around to understand better what is a digest loop and how does it work? So, first, I will do something pretty weird in the playground controller.
I will create a new watch expression with an empty listener. In the watcher function, I will do a small side effect that brings to the console to count how many times this watcher was called, I am going to also declare a variable called times, and I'm going to increase it by one, every time the watcher is called. The watcher function will just return to zero just to return something identical every time it is called.
Let's open the web up and see what happens. We see two calls to this watcher whenever we refresh the page. For now, I am going to ignore this (mumbles) and I'm not going to explain them. We're going to focus on what happens when we run a digest loop. To manually run a digest loop, I am going to do something again, a bit strange in our controller. I'm going to call a set timeout function which will run the current function after one second.
I'm going to press it the value, thousand, because a thousand milliseconds is one second. In said timeout, I'm going to call dollar apply. Which should start a digest loop and before that, I'm going to bring to the console, that this timeout happened. If what I said earlier is true, every time we (mumbles) the apply function, all the watchers should be called, which means the watcher here and the console log on line 15 should run and we should see another call to this console dot log.
As we can see, after one second, the timeout happened and the watcher was called. The apply code triggers all watchers to run and check their values to see if their values has changed and if any of the watchers was dirty it will run all the watchers again. This is the heart of (mumbles) and understanding this section will give you insight on exactly how (mumbles) operates. We'll do something else now.
We're going to add another statement here in the timeout that will change the value of vm dot force to 20 before we run the digest loop. Let's look it up and see what happens. If you notice, carefully, we see two calls to the watcher. The watcher was called two times but another thing just happened. I'm going to refresh the page and please have a look at the HTML itself at this section and see what happens to the value of force.
After one second, the value changed from 30 to 20. So, after we change the value of force and we call the digest loop, all the bindings get updated. The bindings in (mumbles) are implemented the same way watchers are implemented. Actually, every time you use a binding in (mumbles) you are actually using a new watch statement behind the scenes. Let's do another last experiment. We'll change the value of force, but this time we'll remove the code to dollar apply and try to guess what will happen.
We didn't see any calls to our watcher in the log, which makes sense. The digest loop wasn't called to trigger it. Another side-effect we see, is that the bindings haven't changed either. This happened for the same reason. To update the bindings, (mumbles) uses the same mechanism of watchers and digest. If there was no digest, the bindings will not get updated. The digest loop algorithm is pretty simple. Go over all watchers and run them.
If one of them is dirty, run it's listener and do another round of dirty checking. Since this dirty watch might have changed some values that made other watchers dirty as well. Since watchers may run several times the digest process is called the digest loop. It's a loop that runs until nothing is dirty anymore. There are some things you should be aware of when implementing a watcher. It shouldn't have side-effects.
It shouldn't change variables in your code. In our example, we updated the times variable we did it only to explain the digest mechanism. This type of coding production is a big no-no. It shouldn't be slow. You should write pretty simple watcher functions. Even one slow watcher function will slow down the whole digest loop, which means the whole application will be slowed down. It is best if the watcher function doesn't access the (mumbles).
Watching the (mumbles) of an element, for example is usually a bad idea. Since it will cause the browser to render in every digest cycle and might also reduce the performance of the web app in many cases.
This advanced AngularJS course helps you explore the connected worlds of $scope and the digest cycle. Instructor Iftach Bar explains scope and inheritance, goes behind the scenes of the digest loop, and teaches both manual and automatic data binding approaches. Plus, learn how to integrate external libraries, diagnose performance issues, and debug your applications.
- $scope and controllers
- $scope built-in variables and methods
- $scope prototype inheritance
- Manual data binding with $scope.$watch
- The digest loop
- Get the $scope in the console
- Forcing $digest