当控制器变为后台(或无效)时需要停止正在进行的操作

Need to stop ongoing operation when controller becomes background (or invalid)

我正在编写我的第一个 AngularJS 应用程序。着陆页有两个 links #/view1#/view2。每个 link 都会调用单独的控制器来单独渲染 <div ng-view></div>

view1Ctrl会定期从服务器获取数据。我可以看到 ajax 每 X 秒在控制台中调用一次。现在我点击 #/view2,应用程序应该使用 view2Ctrl。我预计 view1Ctrl 不应再从服务器获取数据。但实际上确实如此。

.controller('View1Ctrl', function($scope, $http) {
  $scope.update = function() {
    $http.get('/api/foo')
      .success(function(data) { /* got new data */ })
      .error(function(data) { /* error occurred */ })
      .finally(function() {
        setTimeout($scope.update, 1000);
      });
  }
  $scope.update();
});

我有两个问题:

  1. 控制器在初始化后是否始终处于活动状态。
  2. 停止任何后台控制器的最佳做法是什么?我的想法是检查 $location.path().

更新 1:

控制器真的被销毁了。但是操作 update 会自己调用它,所以操作会被调用到无穷无尽。

我当前的解决方法是检查当前位置是否已更改。所以它有效。我正在寻找一种更优雅的方式,如果它存在的话。

.controller('View1Ctrl', function($scope, $http) {
  $scope.update = function(path) {
    $http.get('/api/foo')
      .success(function(data) { /* got new data */ })
      .error(function(data) { /* error occurred */ })
      .finally(function() {
        if (path === $location.path()) {
          setTimeout($scope.update, 1000, path);
        }
      });
  }
  $scope.update($location.path());
});

更新二:

更好的方法是观察销毁并取消正在进行的超时承诺。谢谢@pankajparkar

.controller('View1Ctrl', function($scope, $http, $timeout) {
  var timeoutPromise;
  $scope.$on("$destroy", function(){
    $timeout.cancel(timeoutPromise);
  });
  $scope.update = function() {
    $http.get('/api/foo')
      .success(function(data) { /* got new data */ })
      .error(function(data) { /* error occurred */ })
      .finally(function() {
         timeoutPromise = $timeout($scope.update, 1000);
      });
  }
  $scope.update();
});

我想你在 body 标签或你的 ng-view 的父标签上提到了 ng-controller,在你的情况下你应该从你的 $routeProvider 加载控制器来处理它,

配置

app.config(function($routeProvider) {
  $routeProvider
    .when('/view1', {
      templateUrl: 'view1.html',
      controller: 'view1Ctrl' //load specific controller from here
    })
    .when('/view2', {
      templateUrl: 'view2.html',
      controller: 'view2Ctrl' //load specific controller from here
    })
    .otherwise({
      redirectTo: '/view1'
    });
});

HTML

  <div class="wizard">
    <ng-view></ng-view>
  </div>

以下是您问题的答案。

  1. 现在,当 $routeProvider 加载 view1.html 时,view1Ctrl 将存在,一旦用户导航到 view2.htmlview1Ctrl 将停止工作 view2Ctrl 将出现在你提到的路线配置中。
  2. 您应该始终使用 $routeProvider$stateProvider(angular-ui-router) 在您的应用程序中设置路由,并在基础上加载 templatescontroller路由。不用勾选 $location.path()

Working Plunkr

更新

您的问题出在重复的函数调用上,即使在控制器作用域从 DOM 中消失后,它仍然在后台 运行。 在重定向到其他控制器时清除此功能的最佳方法。 我建议你把你的 $timeout 承诺(你使用 setTimeout 将它更改为 $timeout)在一个 java 脚本变量中,并在离开时取消它(注销控制器) ).离开控制器时 $destroy 事件由 angular 调度,这类似于控制器的 destruct-or,您可以使用它,您可以取消其中的 $timeout 承诺。

代码

var timeoutPromise = setTimeout($scope.update, 1000);
$scope.$on("$destroy", function(){
    $timeout.cancel(timeoutPromise);
});

Plunkr 取消了 $timeout 的承诺。 Reference Link

希望对您有所帮助,谢谢。