20

The code is simple:

<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <script>document.write("<base href=\"" + document.location + "\" />");</script>
  <link rel="stylesheet" href="style.css">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
</head>
<body ng-controller="MainCtrl">
  Hello {{name()}}!
</body>
</html>
<script>
var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.name= function() {
    console.log("---name---:" + new Date());
    return "Freewind";
  };
});

</script>

You can see there is a name function and we invoke it in the body only one time. But in the console, it prints twice of ---name---::

---name---:Wed Feb 20 2013 14:38:12 GMT+0800 (中国标准时间)
---name---:Wed Feb 20 2013 14:38:12 GMT+0800 (中国标准时间)

You can see a live demo here: http://plnkr.co/edit/tb8RpnBJZaJ73V73QISC?p=preview

Why the function name() has been invoked two times?

Freewind
  • 193,756
  • 157
  • 432
  • 708
  • it is very difficult sometimes to get to the *exact* question you are looking for. Thx for this! – Eugene Jun 22 '14 at 15:55
  • 1
    Though you can restrict it to call only once by using init variable ref: http://plnkr.co/edit/l57V2rzX51JumtAtWXBN?p=preview hope this helps. – saurabh Sep 09 '16 at 09:45

1 Answers1

42

In AngularJS, anything wrapped in double curly braces is an expression that gets evaluated at least once during the digest cycle.

AngularJS works by running the digest cycle continuously until nothing has changed. That's how it ensures the view is up-to-date. Since you called a function, it's running it once to get a value and then a second time to see that nothing has changed. On the next digest cycle, it will run at least once again.

It's generally a good idea to only call idempotent methods (like name) from the template for this very reason.

Josh David Miller
  • 120,525
  • 16
  • 127
  • 95
  • 2
    +1, also to make it clear: angularjs may call any function bound in the view at **any** point during digest phase and **multiple** digest phases might be executed. It makes **no guarantee** about the number of calls. – Liviu T. Feb 20 '13 at 08:48
  • Right! The *only* thing guaranteed is that it will run *at least* once. – Josh David Miller Feb 20 '13 at 17:48
  • @JoshDavidMiller thank you for this. Is there a way to bind the result of some computation to a view without using a method call in the brackets? For example: http://plnkr.co/edit/cFHa6uhYbZc6QwNoLw10?p=preview – desbo Jul 14 '14 at 13:11
  • 1
    @desbo You can manually maintain a scope variable, which is usually the preferred approach if the method performs any computation; the controller then changes the scope variable as necessary (manually or through watches). But the reason your Plunker doesn't work is that `count` is *assigned*, not referenced. Demo of both: http://plnkr.co/edit/miXH6b6HsRWwDNKVgiPP?p=preview – Josh David Miller Jul 14 '14 at 14:52
  • Ah, thanks. So would you advise against exposing services directly in controllers, as I did, and creating wrappers for the service methods in the controller instead? – desbo Jul 14 '14 at 17:19
  • 1
    That can depend upon particulars. *In general*, I place services on scopes that represent *things*, but I do not place any services on the scope that represent *actions*. That is, a `userService` would not go on the scope, but a `currentUser` would. This is a compromise for separation of concerns. I will note, however, that there is some disagreement here as to the best practice. – Josh David Miller Jul 14 '14 at 20:38
  • I am new user of AngularJS. I find this wird. So, all controller methods should be idempotent ? Please share documentation if you do have? - thx – minchiya Jan 30 '15 at 16:59
  • @minchiya - All controller methods being idempotent would not be a good rule of thumb, but one should definitely keep performance in mind when choosing to have methods that are evaluated during the digest. Not all controller methods are; only those bound as expressions will be evaluated during the digest. What kind of documentation are you looking for? – Josh David Miller Jan 31 '15 at 03:00
  • Thank you. Concerning documentation, I started using angularJs. But I need to better understand what is happening behind the scene, like the digest cycle... If you know a nice tutorial I would be grateful – minchiya Jan 31 '15 at 05:36
  • The [guide](https://docs.angularjs.org/guide) has a collection of pretty good tutorials (including an official one). Also check out the great videos on [egghead](https://egghead.io/). But if you're really looking to learn about the *internals*, the guide pages on [bootstrapping](https://docs.angularjs.org/guide/bootstrap) and the [compiler](https://docs.angularjs.org/guide/compiler) are must-reads. – Josh David Miller Jan 31 '15 at 06:00
  • You can surely get rid of double execution of such functions by adding a init variable to carry its value. ref: http://stackoverflow.com/a/39408368/1666582 – saurabh Sep 09 '16 at 09:37
  • 1
    @saurabh: I agree with using variables instead of functions for all but trivial things. However, it does *not* prevent the expression from being evaluated more than once. Whatever is within the curly braces will be evaluated twice. If it's a function, it will be called twice, but if it's a variable, its value will still be pulled *twice* - because something else in the cycle could have changed it. – Josh David Miller Sep 09 '16 at 17:24