27

我每 2 秒轮询一次我的数据,以使它们在页面上保持更新。我的问题是当我访问另一个页面时,超时保持有效。访问新页面时如何取消超时?

function IndexCtrl($scope, $timeout, RestData) {
    $scope.rd = {};

    (function getRestDataFromServer() {
        RestData.query(function(data){
            $scope.rd = data;
            $timeout(getRestDataFromServer, 2000);
        });
    })();
}

//编辑我找到了一个解决方案,但我不确定它是否是一个好的解决方案。当我将超时保存到 $rootScope 时,我可以在所有其他控制器中取消它。

function IndexCtrl($scope, $rootScope, $timeout, RestData) {
    $scope.rd = {};

    (function getRestDataFromServer() {
        RestData.query(function(data){
            $scope.rd = data;
            $rootScope.prom = $timeout(getRestDataFromServer, 2000);
        });
    })();
}

function newPageCtrl($scope, $rootScope, $timeout) {
    $timeout.cancel($rootScope.prom); 
}
4

2 回答 2

65

更改路由时会广播几个 Angular 事件。IndexCtrl您可以在使用中收听它们$scope.$on并采取相应措施:

$destroy 事件

var promise = $timeout(getRestDataFromServer, 2000);
...

$scope.$on('$destroy', function(){
    $timeout.cancel(promise);
});

$locationChangeStart

var promise = $timeout(getRestDataFromServer, 2000);
...

$scope.$on('$locationChangeStart', function(){
    $timeout.cancel(promise);
});

$timeout()返回一个承诺对象。这个对象可以提供给$timeout.cancel()函数来取消超时。

于 2013-06-17T07:54:02.467 回答
15

Stewie 的回答是完美的。我只是想分享这个我使用而不是$timeout直接使用的简单辅助函数,这样我就不必再考虑这个问题了:

function setTimeout(scope, fn, delay) {
    var promise = $timeout(fn, delay);
    var deregister = scope.$on('$destroy', function() {
        $timeout.cancel(promise);
    });
    promise.then(deregister, deregister);
}

我将此函数添加到名为 的服务miscUtils中,并且我注入该服务而不是注入$timeout. 然后,例如,创建一个每 30 秒运行一次的“更新”函数,直到$scope被销毁:

update();
function update() {
    // do the actual updating here
    miscUtils.setTimeout($scope, update, 30000);
}

为那些对正在发生的事情感到困惑的人编辑deregister

这个函数为$destroy事件注册一个监听器,但是一旦超时完成就不再需要了;不再有取消的超时时间。scope.$on返回一个函数,该函数在调用时会取消注册该侦听器。因此,promise.then(deregister)一旦超时完成,就清除不再需要的侦听器。

于 2014-06-13T19:28:06.637 回答