Почему я получаю два вызова метода в Angular JS?

У меня есть следующий пример:

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
  $scope.testMethod = function() {
    alert('hi');
  }
});
<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="1.5.0" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
</head>

<body ng-app="myApp">
  <div ng-controller="myCtrl">
    {{testMethod()}}
  </div>
</body>

</html>

Ответ 1

Когда вы используете функции в выражениях привязки, Angular будет переоценивать выражение на каждой фазе $digest. Причина этого в том, что функции могут возвращать ответ, но нет возможности для Angular знать, не изменится ли результат в следующем вызове функции.

Angular гарантирует, что в этом случае он покажет самое последнее правильное значение до даты - путем вызова функции каждый раз, когда происходит изменение области.

Вы увидите, что люди называют эту фазу "$ digest". Это может произойти по многим причинам. Ради этого объяснения я упрощаю вещи. Если вы хотите узнать больше, прочитайте https://docs.angularjs.org/guide/scope

Как правило - избегайте привязки к функции. Вместо этого запомните ответ функции в переменной $scope и привяжите к ней. Привязка много раз к функции может привести к проблемам с производительностью, когда количество привязок растет в вашем проекте.

EDIT - ответьте на комментарии sahbeewah (см. ниже)

Измените пример публикации. Откройте консоль и запустите код ниже.

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
  var i = 0;

  $scope.testMethod = function() {
    alert('hi');

    i++;
    return i; // Return a different value every time
  }
});
<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="1.5.0" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
</head>

<body ng-app="myApp">
  <div ng-controller="myCtrl">
    {{testMethod()}}
  </div>
</body>

</html>

Ответ 2

avladov ответ правильный, но, возможно, не распространяется на то, что спрашивали sahbeewah. Обновление ответа является объяснительным, но, честно говоря, ответ сводится к гораздо более простой точке.

  • Angular объединяет всех наблюдателей со специальным свойством (называемый last в v1.4.10).

  • Начальное значение last - это функция initWatchVal(), которая является частным значением в angular и, следовательно, вы не можете вернуться без серьезных хаков.

  • Грязная проверка работает, оценивая выражение и сравнивая с предыдущей оценкой (значение last).

  • Если эти значения не совпадают, запланирован новый раунд оценок.

Точка: поскольку вы не можете вернуть начальное значение, новый раунд оценок всегда запланирован после первой оценки новых наблюдателей.