web-dev-qa-db-ja.com

新しいコントローラーを開始するときに$ timeoutを停止する

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); 
}
27
fraherm

ルートが変更されているときにブロードキャストされているAngularイベントがいくつかあります。_$scope.$on_を使用してIndexCtrl内でそれらをリッスンし、それに応じてアクションを実行できます。

$ 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()はpromiseオブジェクトを返します。このオブジェクトを$timeout.cancel()関数に提供して、タイムアウトをキャンセルできます。

64
Stewie

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_を注入する代わりにそのサービスを注入します。次に、たとえば、_$scope_が破壊されるまで30秒ごとに実行される「更新」関数を作成します。

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

Editderegisterで何が起きているのか混乱している人のために:

この関数は_$destroy_イベントのリスナーを登録しますが、タイムアウトが完了すると不要になります。キャンセルするタイムアウトはなくなりました。 _scope.$on_ は、呼び出されたときにそのリスナーの登録を解除する関数を返します。そのため、promise.then(deregister)は、タイムアウトが完了するとすぐに、不要になったリスナーをクリーンアップします。

15
Eric Simonton