How often does the AngularJS digest loop run?

后端 未结 3 1770
无人及你
无人及你 2021-02-02 08:03

When discussing the merits of AngularJS, two-way data binding is often touted as a major benefit of Angular over other JS frameworks. Digging deeper, the documentation suggests

相关标签:
3条回答
  • 2021-02-02 08:24

    Short direct answer to the main question is "NO", angular doesn't automatically trigger digest loop.

    TL;DR answer:

    Digest loop is designed to run dirty check over POJO models associated with Angular scope instances, so it only needs to run when a model might be changed. In a single page Web application running inside Browser, the following actions/events could lead to a model change

    1. DOM events
    2. XHR responses firing callbacks
    3. Browser's location changes
    4. Timers (setTimout, setInterval) firing the callbacks

    Correspondingly, Angular trigger digest loop at, for instance

    1. input directives+ngModel, ngClick, ngMouseOver etc.
    2. $http and $resource
    3. $location
    4. $timeout

    Try to answer those bonus questions from my understanding:

    1. ngModel directive often used with angular input directives (text, select etc) together, and the laters will listen on "change" events and call $setViewValue API exposed from ngModelController in order to sync back dom value. During the sync process, ngModelController will make sure to trigger digest loop.
    2. digest loop is different from JS event loop, the later is concept of JS runtime (checkout the great visualised session https://www.youtube.com/watch?v=8aGhZQkoFbQ) which run against event queue and remove consumed event from the queue automatically, but digest loop never remove watch from its watch list unless you explicitly unwatch.
    3. the number of digest loops per second depends on the efficiency of all watch callbacks being executed through the loop . If some bad code took one second to finish, then this digest loop would cost more than 1 sec.

    So some key practices for avoid angular performance pitfalls are

    1. Watch callback should be coded as simpler/efficient as possible, for example detach complicated algorithm code to, for example, worker threads
    2. Proactively remove a watch if it is not used anymore
    3. Prefer to call $scope.$digest() instead of $scope.$apply() if applicable, $digest() only run part of scope tree and ensure the models associated under the subtree is reflecting to view. But $apply() will run against entire scope tree, it will iterate through more watches.
    0 讨论(0)
  • 2021-02-02 08:30

    Angular digests are triggered - they don't happen through polling.

    Code executes, after code is done, angular triggers a digest.

    Example:

     element.on('click', function() {
         $scope.$apply(function() { 
             // do some code here, after this, $digest cycle will be triggered
         });
     });
    

    Angular will also trigger a $digest after the compile/link phase:

    Compile > Link > Digest
    

    And as to how many digest cycles are triggered? It depends on how soon the scope variables stabalise. Usually it takes at least 2 cycles to determine that.

    0 讨论(0)
  • 2021-02-02 08:30

    I believe this is what happens. AngularJS made a smart assumption that model changes happen only on user interaction. These interactions can happen due to

    • Mouse activity (move, clicked etc)
    • Keyboard activity (key up, key down etc)

    AngularJS directives for the corresponding events wrap the expression execution in $scope.$apply as shown by @pixelbits in his example. This results in digest cycle.

    There are some other events too where AngularJS triggers the digest loop. $timeout service and the $interval service are two such examples. Code wrapped in these service also results in digest loop to run. There maybe be some other events\services that can cause digest cycles to execute but these are the major ones.

    This is the very reason that changes to model outside the Angular context does not update the watches and bindings. So one needs to explicitly call $scope.$apply. We do it all the time when integrating with jQuery plugins.

    0 讨论(0)
提交回复
热议问题