我使用current-time
使用$timeout
指令,它似乎在一个单独的控制器中调用函数。我很困惑为什么会这样,我认为控制器包含它们自己的范围并彼此隔离?
基本上,myFunction
指令currentTime
发生时会调用$timeout
。这是一个大问题吗?这会给我带来麻烦吗?有人能帮我理解这种行为吗?这是一个plunker,它展示了我正在谈论的行为。
这是我的HTML
:
<html ng-app="myapp">
<head> <!-- using Angular version 1.2.0-rc3 --> </head>
<body>
<div ng-controller="TimeController">
<span current-time></span>
</div>
<div ng-controller="MyController">
<span class="grrr">{{myFunction()}}</span>
</div>
</body>
</html>
My Angular code:
var myapp = angular.module('myapp', []);
// just to show that I'm using my currentTime directive in separate controller.
// but it still happens if remove TimeController.
myapp.controller('TimeController', ['$scope', function($scope) {
console.log('entering TimeController');
}]);
myapp.controller('MyController', ['$scope', function($scope) {
$scope.myFunction = function() {
console.log('calling myFunction');
return 'myFunction was last called @ ' + new Date().toString();
};
}]);
// continuous update for time
myapp.directive('currentTime', ['$timeout', function($timeout) {
return function(scope,element,attrs) {
function updateTime() {
$timeout(function() {
element.text(new Date().toString());
updateTime();
}, 1000);
};
console.log('start clock');
updateTime();
};
}]);
答案 0 :(得分:5)
<强> TL:DR 强>
将指令更改为
$timeout(function() {
element.text(new Date().toString());
updateTime();
}, 1000, false);
它不会触发您的myFunction()
长篇故事
当你这样做时
<span class="grrr">{{myFunction()}}</span>
你基本上告诉Angular,span的内容应该总是等于调用myFunction()
的结果。
现在,Angular不知道你的函数依赖什么类型的变量来返回结果,所以每当有什么变化时,它需要再次调用该函数来查看它是否返回其他东西(这称为脏检查)。请记住这一点,一旦我们查看该指令,这将非常重要。
在指令中,您每秒都在运行$timeout
。这触发了$digest
循环,这基本上是Angular检测事物是否发生变化的方式。在执行此操作的过程中,它会检查所有范围,这意味着它还将调用您的myFunction()
以查看该指令是否确实影响了该范围。这就是它不断被召唤的原因。
现在,如果您不想要这种行为,您可以绑定到变量而不是函数,或者如果您像我一样好奇,请转到$timeout的源代码。我想你也可以查看documentation,但说实话,大多数Angular文档并不是那么好,所以我通常先找到源代码。
有一个名为invokeApply
的可选标志(这个甚至是文档),如果你将其设置为false,那么$timeout
将不会触发脏检查。
答案 1 :(得分:2)
这就是$ digest循环的工作方式。当触发$ digest时,angular将遍历所有$ watch表达式并确定它们是否已更改。对于所有范围内的所有$ watch表达式都会发生这种情况 - 一个称为脏检查的过程。
调用myFunction()的原因是因为绑定表达式导致了对它的隐式$ watch:
{{myFunction()}}
这是正常的,无需担心。
定期触发$ digest循环的原因是因为你的$ timeout函数。默认情况下,它将在$ apply块中调用您的超时函数,这反过来会触发$ digest。您可以通过将false作为第三个参数传递给$ timeout来禁用此行为。
我建议您使用$interval
代替$timeout
。它更适合这种情况。