Tuesday, September 8, 2015

Getting Inside Angular: $scope.$evalAsync

If you want something to be executed while a digest is in progress, then $scope.$evalAsync is probably what you're looking for.

What does $scope.$evalAsync do?

When a digest is in progress, Angular is looping through all the watches and comparing values to detect if any changes have occurred. As the listener function from a watch could cause a change to another watched property, this loop can run multiple times per digest. $scope.$evalAsync adds the supplied function to a queue that will be drained at the beginning of the next loop in a digest cycle. It won't wait for the current digest cycle to complete but will execute the $evalAsync'ed function before starting the next loop through all the watches. If a digest is not in progress, one will be scheduled when a function is added to the async queue.

When would you want to use it?

A good explanation of when you would want to use $scope.$evalAsync can be found here: http://stackoverflow.com/questions/17301572/angularjs-evalasync-vs-timeout

In summary, as it queues work to occur outside of the current stack frame:
  • In a Controller: it will run before the DOM has been manipulated by Angular (take caution as your change could be overwritten) and therefore, before the browser renders
  • In a Service: it will run after the DOM has been manipulated by Angular but before the browser renders
If your change is going to affect something that is being rendered, $evalAsync will prevent a flicker from occurring as its work will occur before rendering.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  
  $scope.$watch(
    function (scope) { return scope.name; },
    function (newValue, oldValue, scope) {
      
      console.log('First watch executed \nAdding $evalAsync');
      scope.$evalAsync(function (scope) {
        
        console.log('$evalAsync executed');
        scope.newValue = "new value!";
      });
    }
  );
  
  $scope.$$postDigest(function () {
    
    console.log('$$postDigest executed. Digest completed');
    console.log($scope.newValue);
  });
});

View on Plunker (open the developer tool's console).

The above example ensures that $evalAsync is being called (line 9) during a digest by calling it in the listener function of a watch. The work that is being added to the async queue logs a message out to the console to indicate that the work has been executed and then updates a value on the scope. Line 17 adds a function to the post digest queue* to indicate when the digest has completed.

From the output it is clear to see that the function that was added to the async queue was in fact executed during the already in progress digest.

*The post digest queue is drained once all the change detection loops of the watches have completed and is the last step of a digest that you can interact with. However, the Angular team would prefer that you don't use it--or that you take great care if you do--by marking the $$postDigest function private by prefixing it with two dollar signs.

Performance considerations

Adding to the async queue is either going to cause a new digest to occur or if one is in progress, for it to loop one more time through the watches. If the queued work causes changes to other properties that are under watch, this will lead to additional loops. Angular has a mechanism to prevent a digest from continuing forever and will only allow 10 loops to occur before the digest is terminated (known as TTL: Time To Live). As you cannot control at what point during a digest (in other words, how many loops it has already performed) your work is being added, it could be approaching its TTL limit. This is something to consider when using $evalAsync.

Versus $scope.$applyAsync

Both $applyAsync and $evalAsync are tools that help you get around "$digest already in progress" errors. In my opinion, $applyAsync is the safer option as this queue will be flushed before a new digest begins. This will reduce the likelihood that your work will cause a digest to be terminated due to reaching the TTL limit. There is the potential though that using $applyAsync will cause a flicker as you will be relinquishing control back to the browser before your queued work is executed. If the browser decides to render first, then a flicker could occur. Some might prefer $evalAsync for this reason as it won't leave them at the mercy of the browser's event loop.

//Code, rinse, repeat

9 comments:

  1. Very nice post here and thanks for it .I always like and such a super contents of these post.
    Excellent and very cool idea and great content of different kinds of the valuable information's.

    Java training in Bangalore



    ReplyDelete
  2. Thank you for an additional great post. Exactly where else could anybody get that kind of facts in this kind of a ideal way of writing? I have a presentation next week, and I’m around the appear for this kind of data.
    Data science course in bangalore | Data Science training with placement in Bangalore

    ReplyDelete
  3. Games are fun. Come to us and play we have new casino games online .Excitement and emotions are what a casino is.

    ReplyDelete
  4. Thanks for the informative article. This is one of the best resources I have found in quite some time. Nicely written and great info. I really cannot thank you enough for sharing.
    microsoft azure training in bangalore
    rpa training in bangalore
    best rpa training in bangalore
    rpa online training

    ReplyDelete
  5. Amazing article. Your blog helped me to improve myself in many ways thanks for sharing this kind of wonderful informative blogs in live. I have bookmarked more article from this website. Such a nice blog you are providing ! Kindly Visit Us @ Best Travels in Madurai | Tours and Travels in Madurai | Madurai Travels

    ReplyDelete
  6. Thanks For Sharing The information The Information Shared Is Very Valuable Please Keep Updating us The Information shared Is Very Valuable Python Online Course Data Science Online Course Aws Online Course

    ReplyDelete
  7. Information from this blog is very useful for me, am very happy to read this blog Kindly visit us @ Luxury Watch Box | Shoe Box Manufacturer |  Candle Packaging Boxes

    ReplyDelete