为什么我在Angular JS中获得两个方法调用?

Gan*_*abu 10 javascript function angularjs

我有以下示例:

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

<head>
  <script data-require="angular.js@1.5.0" 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>
Run Code Online (Sandbox Code Playgroud)

我在视图模板中只调用了一次该方法.但为什么要执行两次呢?

avl*_*dov 12

当您在绑定表达式中使用函数时,Angular将在每个$ digest阶段重新评估表达式.这背后的原因是函数可以返回响应,但是Angular无法知道结果在下一个函数调用中是否会发生变化.

Angular确保在这种情况下以唯一可能的方式显示最新的正确最新值 - 通过每次范围发生变化时调用函数.

你会看到人们称之为"$ digest阶段".它可能由于许多原因而发生.为了这个解释,我简化了一些东西.如果您想了解更多信息,请阅读https://docs.angularjs.org/guide/scope

作为一般规则 - 避免绑定到函数.而是记住$scope变量中的函数响应并将其绑定到它.在项目中绑定计数增加时,多次绑定到函数可能会导致性能问题.

编辑 - 回答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
  }
});
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>

<head>
  <script data-require="angular.js@1.5.0" 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>
Run Code Online (Sandbox Code Playgroud)

出于示例目的,$scope.testMethod每次调用时返回不同的值非常重要.

你会注意到以下几点:

  • "嗨"警报将多次显示
  • 多次看到后会出现以下错误:

    错误:[$ rootScope:infdig] 10 $ digest()迭代达成.中止!

所以发生了什么事?每当我们改变$scope状态时,角度运行另一个消化阶段,直到它"稳定"(没有更多的变化).连续10个$摘要阶段有限制.

在附加控制器的线程调用角度调用$ digest然后,因为我们更改$ scope,它再调用一个摘要.如果我们从代码中删除所有绑定,则只会发生一个摘要.

我们可以轻松检查这一点.{{testMethod()}}从示例中删除该行,然后在角度代码中放置一个断点:$ digest,第16700行(角度1.5.0).
在这条线上,你会看到if ((dirty || asyncQueue.length) && !(ttl--)) {.

您的断点现在只会被击中一次.我们看看上面两行.Angular团队在那里写了一篇有趣的评论:

// `break traverseScopesLoop;` takes us to here
Run Code Online (Sandbox Code Playgroud)

这是一个自我解释的评论,如果我们走到16629行,我们会看到

do { // "while dirty" loop
Run Code Online (Sandbox Code Playgroud)

名为"dirty"的代码中有一个创建do...while循环的变量.虽然范围很脏(检测到更改),但您将保持此循环.更改是任何类型绑定以任何方式使用的任何范围变量的任何更改($ watch).

这就是我们在这里有2个$ digest阶段的原因.

你可以在这里找到Angular 1.5 .出于调试目的,我已切换到非缩小版本.