【问题标题】:angular $scope.$watch with an function that returns a promise带有返回承诺的函数的角度 $scope.$watch
【发布时间】:2014-07-18 13:14:31
【问题描述】:

我正在尝试对异步函数的返回值设置监视,但一直运行到无限摘要循环。这是我的 $watch

  $scope.$watch(function(){
    var friendsCount = PublicUserData().then(function(data){
      console.log(data.length);
      return data.length;
    });
    return friendsCount;
  }, function(newValue, oldValue) {
    console.log("change"+ newValue);
  });

我可以在 chrome 控制台中看到 console.log 都被调用,但第二个(在回调中)比第一个更频繁地被调用。

PublicUserData 使用$q

.factory('PublicUserData', function($http, $q){
  return function(){
    var defer = $q.defer();
    $http.get('/api/v1/users/').then(function(data){
      defer.resolve(data.data.users);
    })
    return defer.promise;
  }
})

我尝试了一些方法,例如将 watch 表达式设置为我的 $watch 之外的 $scope,但最终返回的是工厂代码,而不是工厂的返回值。

是否可以将$watch 与实现承诺的函数一起使用?还是我应该使用其他东西?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    你真的真的真的真的不想做来自$watch 的 AJAX 请求。真的。

    Angular 使用脏检查,并且您的 $watch 函数将在每次 $scope 发生任何变化时重复调用。如果你能让它工作,它会在向服务器发送垃圾邮件时完全破坏你的应用程序的性能。

    看起来你想要做的是有一个计数器或显示有多少朋友登录的东西?使用服务器事件或轮询机制可以更好地解决这个问题,轮询是最容易实现的。

    请考虑这样的事情:

    $interval(function() {
        PublicUserData().then(function(data) {
            $scope.data.friendsCount = data.length;
        });
    }, 1000);
    

    这将每秒轮询一次服务器(这可能是多余的,但比尝试在$watch 中执行此操作的频率要低得多)并使用正确的值更新$scope

    【讨论】:

    • 啊,我明白了。我无法弄清楚为什么它会导致摘要循环。你让我想到了另一种方法来解决这个问题,干杯!
    • @user2936314 查看可让您在应用程序中提供 websocket 或长池通信的解决方案。它会让你将信息从服务器推送到 ui,而不是轮询。例如,我们在基于 Java 的应用程序中使用 Atmosphere
    【解决方案2】:

    如果你已经有了一个承诺,为什么还要 $watch?

    PublicUserData().then(function(data){
      $scope.friendsCount = data
    });
    

    如果您需要在间隔内运行它,最佳性能会给出 $timeout

    callForFriendsCount = function () {
      PublicUserData().then(function(data){
        $scope.friendsCount = data
        $timeout(callForFriendsCount, 1000)
      });
    }
    

    $timeout 是一个更好的主意,因为在任何情况下,如果旧调用需要超过 1000 毫秒,它将与最新调用重叠,使用 $timeout 可以避免这种情况

    【讨论】:

      【解决方案3】:

      只是为 ivarni 的出色答案提供另一个类似的解决方案。如果您想轮询(无论是使用超时还是间隔),您可以在工厂中执行此操作,只需使用一个简单的范围变量:

      var app = angular.module('plunker', []);
      
      app.controller('MainCtrl', function($scope, PublicUserData) {
      
        $scope.pollData = PublicUserData.pollData;
      
      });
      
      
      app.factory('PublicUserData', function($http, $q, $interval){
      
      
        var srv = {
          pollFn: function() {
            srv.stopInterval = $interval(function() {
      
              srv.pollData.friendCount++;
              console.log('polled');
      
            }, 1000);
          },
          pollData: {friendCount: 0, other: {}},
          stop: function() {
             $interval.cancel(srv.stopInterval);
          }
      
        }
      
        srv.pollFn();
      
         return srv; 
      });
      

      演示:http://plnkr.co/edit/0467sypyeg0Wpdr4302k?p=preview

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-24
        • 1970-01-01
        相关资源
        最近更新 更多