我应该在 angular 控制器中使用 $watch 还是大型函数?

Should I use $watch or a large function in my angular controller?

我有一个提交给第 3 方服务的表单,以便接收 "token"。我可以指定一个回调函数来处理来自第 3 方服务的响应。理想情况下,此响应将是令牌,但它也可以是错误消息。回调函数在我的控制器中。在该函数中,我设置了一些在应用程序流程中前进所需的其他 $scope 变量。

因为我无法在没有更新的 $scope 变量值的情况下继续前进,并且它们正在我的回调函数中设置,我想我被困在 $watch 更新 $scope 变量时触发更多事件或我可以将其余功能放在回调函数中。

选项 1(简化示例):
在 $scope 变量上使用 $watch 在其值更新时向前移动

var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {

     $scope.token = false;

     $scope.$watch('token', function () {  
         doThis();
         for(var i=0; i<len; i++) {
             myFnction("Do Some", MORE_STUFF);
         }

         someObj.fetchGoodStuff($scope.token);             
     });

     $scope.myCallback = function(status, response) {
         if(!response.error) {
             $scope.token = response.token;
         }
    })
}]);



选项 2(简化示例):
从回调函数中向前移动

var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {

     $scope.token = false;

     $scope.$watch('token', function () {  
         doThis();
         for(var i=0; i<len; i++) {
             myFnction("Do Some", MORE_STUFF);
         }

         someObj.fetchGoodStuff($scope.token);             
     });

     $scope.myCallback = function(status, response) {
         if(!response.error) {
             $scope.token = response.token;

             doThis();
             for(var i=0; i<len; i++) {
                 myFnction("Do Some", MORE_STUFF);
             }

             someObj.fetchGoodStuff($scope.token); 
         }
    })
}]);



对我来说,似乎更 "correct" 隔离回调函数的基本功能,在本例中是接收来自第三方服务的响应,并将后续功能放在其他地方。

BUT 我能看到的唯一另一个地方是在 $watch 调用的函数中...并且因为 $scope 变量的值只改变一次每页访问,$watch 在这里似乎不合适。

有人知道收到回复后采取行动的最佳方式吗?

不使用手表。它会在以后造成很多开销和麻烦。仅在绝对必要时使用。您应该尝试改用 promise,并在可能的情况下让 return 为 promise 提供服务。如果您必须 向您的外向服务提供回调(不能return 承诺),请执行以下操作:

myApp.controller('GreetingController', ['$scope', '$timeout', function($scope, $timeout) {

 $scope.token = false;

// Use this promise to simulate various events related to token fetching
var tokenFetched = $q.defer();

$scope.callbackYouMustHave = function(status, response) {
    if (!response.error) {
        tokenFetched.resolve(response.token); // or any other data you need
    } else {
        tokenFetched.reject(status, response); // Error handling
    }
}

tokenFetched.then(function(token) {
    // Triggering a digest with $timeout, a little awkward but better than watch trust me
    $timeout(function() {
        $scope.token = token; // This triggers a digest and changes your view / whatever
    });
    doThis();
    for(var i=0; i<len; i++) {
        myFnction("Do Some", MORE_STUFF);
    }

    someObj.fetchGoodStuff($scope.token);
});

tokenFetched.catch(function(status, response) {
    // error handling
    console.log('error fetching token:', response);
});

那里。完全干净,完全可读。不要使用手表,除非你绝对必须

作为对此的补充,我意识到如果您使用 promises,您可能需要手动触发摘要。我又做了一次编辑

您需要调用多少次第三方服务?你需要每次都调用它还是只需要调用一次?常见的方法是用 returns 承诺的服务包装第 3 方代码。

myApp.factory('My3rdParty', ['$q', '$rootScope', function ($q, $rootScope) {
    return {
        getToken: function () {
            var deferred = $q.defer();
            doSome3rdPartyStuff(function success(token) {
                // we need to trigger a digest because 3rd party lib runs out of
                // angular's digest cycle
                $rootScope.$apply(function (){
                    deferred.resolve(token);
                });
            }, function error(err){
                $rootScope.$apply(function (){
                    deferred.reject(err);
                });
            });
            return deferred.promise;
        }
    }
}]);

在您的控制器中,注入服务并进行调用并使用 promise 继续

myApp.controller('SomeController', ['$scope', 'My3rdParty', function ($scope, My3rdParty) {
    $scope.doSomeAction = function () {
         My3rdParty.getToken().then(function (token) {
             alert("I got the token!");
         }, function (err) {
             alert("I got an error");
         });
    }; 
}]);

如果你需要向用户显示令牌,你可以把它放在 $scope 下, 如果你希望令牌在你的控制器之外被改变(用户改变它,一些其他服务改变它),你可能需要 $watch 它,否则上面的代码应该足够了。