AngularJS的$timeout与JavaScript的setTimeout

我们知道,在JavaScript中,setTimeout()方法用于在指定的毫秒数后调用函数或计算表达式。对应地,AngularJS有$timeout服务,语法也一样。可是,要是想当然地认为这两个没什么区别的话,以后在开发中就可能出现百思不得其解的情况——说多了都是泪啊……

典型代码如下:

setTimeout(function() {
$scope.time = new Date()
}, 1000);

这种情况下,页面中绑定的time变量将不会被自动刷新,那换$timeout呢?

$timeout(function() {
$scope.time = new Date();
});

注意把$timeout服务进行依赖注入,然后发现就好使了。不难理解,在AngularJS中,用AngularJS本身提供的方法或服务肯定没问题,但要是还想用setTimeout()呢?

国外一篇博文AngularJS: use $timeout, not setTimeout提到:

However, if we usesetTimeout()in an AngularJS application we also need to use$scope.$apply()to ensure that any changes to the scope will be reflected elsewhere (i.e. data-bound in a view).

所以,我们要改成这样:

setTimeout(function() {
$scope.$apply(function() {
$scope.time = new Date();
});
}, 1000);

$apply()方法是用于传播Model的变化。其实,需要调用$apply()方法的情况非常少,原因在国外一篇博文AngularJS and scope.$apply中提到:

AngularJS actually calls almost all of your code within an $apply call. Events like ng-click, controller initialization, $http callbacks are all wrapped in $scope.$apply().

在这些情况下,并不需要调用$apply()方法,否则在$apply()方法里面再调用$apply()方法会抛出错误。

当在一个新的执行序列中运行代码,而且这个新的执行序列不是被AngularJS的库的方法创建的时候,才真正需要用到它,这个时候可以将代码用$scope.$apply()包起来,如上面用setTimeout()改后的代码。

最后,以一段话结尾,很切题意:

There are one hundred ways to fix a problem. However, the ultimate solution is, don’t give it any chance to happen.