Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Delaying the $digest() cycle in AngularJS (aaron-gray.com)
45 points by aarongray on Sept 18, 2014 | hide | past | favorite | 14 comments


Time spent in the digest cycle scales proportionally to the product of how often a digest occurs, and how many watches there are - each should be roughly proportional to the size of the application, for an overall quadratic complexity. If watches trigger other watches then this also lengthens the cycle, so the growth is actually more than quadratic in the size of the application - as bad as cubic possibly, if most notifications between modules are accomplished by one watch function setting variables for another watch function to pick up.

Debouncing controls one of the terms - frequency of digest cycles - so the complexity grows somewhere between linear and quadratic. The only scalable solution is to minimize the use of watches. Fortunately, this is also a good idea from a code quality standpoint - watches are an unstructured control flow system, similar to GOTO, and should be avoided even if they were efficient.


> watches are an unstructured control flow system, similar to GOTO

Any callback is a GOTO. in fact, any function call in C like languages IS A GOTO.

So i'm not sure what is the point of saying that.

$scope.$watch is at the center of angularjs architecture,there is no way to avoid it.

And that's what makes angularJS awesome,seamless integration between the view layer and other app layers,without a single explicit event handler registration,mediator,observer,... (except for directives obviously). No JS framework but angularjs does that,not even React that needs a 3rd party library to integrate itself with a domain layer.

That's why angularjs is so easy to use and beats everything else.


> Any callback is a GOTO. in fact, any function call in C like languages IS A GOTO.

If a function call would be a GOTO, then you wouldn't have a stack trace to look at in your debugger.

I'm not sure what is the point in replying to a comment you don't actually understand.

Angular's data binding model has a lot of shortcomings:

    angular.module("app").controller("SomeController", function($scope) {
        setTimeout(function () {
            $scope.someVar = 'happy debugging';
        }, 500);
    });


    angular.module("app").controller("SomeController",   function($scope) {
        setTimeout(function () {
            $scope.someVar = 'happy debugging';
        }, 500);
    });

Your example is stupid

1/ you should use $timeout or you're just asking for troubles.If not then $scope.$apply

2/ use named function expressions

Any async operation in angularjs needs to trigger a digest cycle,that's angular 101. You cant use a framework without actually understanding how it works at first place.

Your point is moot because you are using an example that is a mistake at best , but more like a bad piece of code,in angularjs context.No serious angularjs developper would do that mistake,especially when you are supposed to test that piece of code,using a function you didnt inject in the controller.


Well said.


I used debouncing inside a watch expression. Really useful.

Another performance trick.

If you use ng-hide/show to hide a long list, then make a dummy function that takes the list and the variable for the ng-hide/show and only returns the list when the ng-show is true. This way you don't spend valuable time rendering something that will have css hidden.


ng-if is also useful in these cases.

https://docs.angularjs.org/api/ng/directive/ngIf


Yeah, and the good thing about ng-if compared to ng-show is that it removes the elements from DOM, rather than just hiding them, which is better for large datasets.


Also, maybe this isn't a common issue and would be solved by better designed models but.. using an ng-repeat against a list with some heterogeneous data.. ng-if works well to show only the UI components that apply to the object in question without rendering things for no reason and then hiding them.

For example if you have a list of objects where some particular action might apply only to a portion of them.


I like it. We have seen a significant difference in performance in holding objects in our JS but not putting them in the DOM until the user needs to see them. I think the more you can remove from the DOM, the better.


I had no idea canceling a timeout like that was called debouncing.


The term debounce comes from the hardware world. When you press a physical button it's common place for the contact to bounce, causing the contact to open and close a few times in rapid succession.

So you, debounce the button press to ensure that it only causes one edge or press to propagate to the rest of the circuit.


It goes back to something we used to do in electronics, usually with a Schmitt trigger. The idea was that even a good switch (say, a small contact switch or the like) would create several extra pulses as its internal contacts bounced against each other before settling when activated--hence the name: it removes bounces. :)

Nowadays we can use _.debounce or _.throttle.


Note throttle and debounce are slightly different. Debounce will delay firing until the event causing the timeout reset stops (or pre-fire on the first event and then ignore all subsequent events until they stop for a given interval,) where throttle will fire one event within a given interval no matter how many events it receives (as long as it's >=1.)




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: