Filters in AngularJS can be a big performance hog. As of Angular 1.3, filters are "stateless" by default. This means that given the same input, a filter will not even run, and simply return the previous value.
Angular 1.3 is coming with a lot of really cool features. One of those features is stateless filters.
Here I'm using release candidate one for AngularJS 1.3.0. Stateless filters is coming in release candidate two. And so, I'm going to demonstrate the difference here.
First off, we have a very simple demo. We're keeping track of our watch count and our digest cycle so that you can see not only does it look janky but you can see the digest cycle is taking longer than 15 milliseconds.
If you want to have a smooth, buttery feel in your UI, you want your digest cycle length to be under 15 milliseconds.
The way that I'm making this happen is we have an ng-repeat over a list of items and we're passing each of those items through a filter called longFilter. All that this does is it takes the value of timer.wait and it waits for that amount of time before actually returning from the filter.
And so, we can really fine tunely control how long our digest cycle takes based on these filters in particular. We can increase the number of milliseconds for this time value here.
As I move that up, you can see the digest cycle is starting to take a lot longer. Let's move this back down to something a little bit more reasonable but you can still tell that it's a pretty poor user experience.
While the example is contrived, the problem is not. I have seen this in many production applications where your UI looks pretty janky.
Let's switch over to release candidate two and see what that does for us.
We switched to release candidate two and now it's lightning fast. What it's doing is it's saying that all the filters are now stateless, which means Angular is assuming that as long as the inputs to the filter are the same the output will be the same.
That is not entirely true with the way our filter is constructed here. It is stateful because we're injecting in this timer. That is holding our state for wait.
If you see here, because Angular is assuming that this filter is stateless, as I increase the filter wait time or decrease it it's not updating this because Angular is not rerunning those filters because it's a stateless filter.
We can force it to be stateful by saying longFilter, so the function for our filter, dot stateful is true. Now it is stateful and so it will update.
Now we're basically back to where we were before, which is not a very good experience or we can turn our function for our filter to be stateless.
Instead of injecting in the timer, we'll accept it as an argument to our filter. We'll say wait here and I will, instead of timer.wait we'll just assume wait will be passed to us directly.
Let's turn off this stateful property. Now we need to pass in the wait. In this scope of this controller, it's vm.timer.wait.
Now it's lightning fast and it updates as I make these changes. It doesn't matter what it is that I make it wait. It will take a while to run for the first time but afterwards it doesn't run at all.
If I change it to, let's say, 19. It took a second to run the first time but because it's a stateless filter Angular doesn't even run it when the inputs don't change for the next time around.
That's stateless filters. Really cool. Definitely a huge performance win for some of our longer running filters.