简体   繁体   English

Angular最佳实践:在工厂或控制器中承诺?

[英]Angular Best practice: promise in a Factory or in a Controller?

I have a basic factory in my app that handles API calls. 我的应用程序中有一个处理API调用的基本工厂。 Currently I'm using the form: 目前我正在使用表格:

.factory('apiFactory', function($http){

  var url = 'http://192.168.22.8:8001/api/v1/';

  return {
    getReports: function() {
      return $http.get(url+'reports').then(function(result) {
        return result;
      });
    },
    getReport: function(id) {
      return $http.get(url+'report/'+id).then(function(result) {
        return result;
      });
    }
  }
})

And in my controller I'm handling the promise like so: 在我的控制器中,我正在处理这样的承诺:

.controller('exampleController', function($scope, apiFactory) {

      apiFactory.getReports().then(
        function(answer) {
          if (answer.status==200){
            if (answer.data.status == "error"){
              // DISPLAY ERROR MESSAGE
              console.log(answer.data.msg);
            }
          } else{
            // THROW error
            console.log('error: ', answer);
          }
        },
        function(error){
          console.log('error: ', answer);
        }
      );
    }
  }
})

It seems I could move the promise handling to my Factory instead of doing it in my controller, but I'm not sure if that would have any benefits others than a smaller controller. 似乎我可以将承诺处理转移到我的工厂而不是在我的控制器中进行,但我不确定除了较小的控制器之外是否还有其他好处。

Could somebody explain the best practices regarding this pattern? 有人可以解释有关这种模式的最佳做法吗?

It is ultimately up to you how much data you want to provide to the caller of the service. 最终由您决定要向服务的调用者提供多少数据。 If needed, you could definitely return the HTTP response object to the caller, and have them process the response (which, btw, is always HTTP 2xx, if the promise is resolved rather than rejected). 如果需要,您肯定可以将HTTP响应对象返回给调用者,并让他们处理响应(如果承诺得到解决而不是被拒绝,那么,顺便说一下,总是HTTP 2xx)。

But if you want to isolate the caller from the specifics of how the data got there (maybe it was cached, or supplied via another mechanism), and if you need to post-process the data, then it is advisable to handle the response in the service. 但是,如果您想将调用者与数据的具体方式隔离开来(可能是缓存的,或者是通过其他机制提供的),并且如果您需要对数据进行后处理,那么建议您在服务。

Here's an example: 这是一个例子:

.factory("apiService", function($http, $q){
  var url = 'http://192.168.22.8:8001/api/v1/';

  return {
    getReports: function() {
      return $http.get(url+'reports').then(function(result) {
        var data = result.data;

        if (data === "something I don't accept"){
           return $q.reject("Invalid data");
        }

        var processedData = processData(data);
        return processedData;
      })
      .catch(function(err){
         // for example, "re-throw" to "hide" HTTP specifics
         return $q.reject("Data not available");
      })
    },
    // same idea for getReport
  }
});

Then the controller wouldn't need to care about the underlying mechanism - all it gets is data or a rejection. 然后控制器不需要关心底层机制 - 它获得的只是数据或拒绝。

.controller('exampleController', function($scope, apiService) {
   apiService.getReports()
     .then(function(reports){
        $scope.reports = reports; // actual reports data
     });
})

Off-topic: 无关:

Notice how I changed the name of the service from "apiFactory" to "apiService" . 请注意我是如何将服务名称从"apiFactory"更改为"apiService" I wanted to point that out to remove a possible misconception. 我想指出这一点,以消除可能的误解。 Whether you use .factory or .service or .value what you get as an injectable is always a service instance. 无论您使用.factory还是.service.value ,您获得的注入量始终是服务实例。 .factory is just a mechanism of how this service is instantiated, so the name "apiFactory" is a misnomer. .factory只是这个服务是如何被实例化的机制,故得名"apiFactory"是用词不当。 The only "factory" here is a function that you register with .factory (which could be anonymous, of course): 这里唯一的“工厂”是你注册.factory的功能(当然可以是匿名的):

.factory("fooSvc", function fooSvcFactory(){
   return {
      getFoo: function(){...}
   }
})

Better to keep all the data fetching inside the factory. 最好将所有数据保存在工厂内。 This keeps the controller free from state, and it no longer cares how your factory works. 这使控制器不受状态影响,并且不再关心工厂的工作方式。 If you change how you get data (eg not using $http) your controller shouldn't care, as it just calls getReport() and 如果你改变了获取数据的方式(例如不使用$ http),你的控制器应该不在乎,因为它只是调用getReport()和

A good explanation (see "Resolving Model data, no callback arg binding in Controllers"): http://toddmotto.com/rethinking-angular-js-controllers/ 一个很好的解释(参见“解析模型数据,控制器中没有回调arg绑定”): http//toddmotto.com/rethinking-angular-js-controllers/

Short answer: Handle promises in Factory . 简短回答:处理工厂的承诺。

Why? 为什么?

Problems you face if you handle promises in Controller: 如果您在Controller中处理承诺,您将面临的问题:

Let's say you have 5 Controllers that use the same Factory. 假设您有5个使用相同工厂的控制器。 Now let's say that you want to handle the errors when the promise does not get resolved correctly. 现在让我们假设您希望在未正确解析promise时处理错误。 So in the first controller, you write an error callback (or the catch(exception) more precisely, as you are dealing with promises), that shows you an alert message with the error. 因此,在第一个控制器中,您编写了一个错误回调(或者更准确地说,捕获(异常),因为您正在处理promises),它会显示一条带有错误的警报消息。 When the promise fails, this controller shows an alert with the error message. 当promise失败时,此控制器将显示带有错误消息的警报。 So far, so good? 到现在为止还挺好? Right. 对。 But wait! 可是等等! What about the other 4 controllers? 那4个控制器怎么样? You haven't handled the errors in them. 您尚未处理其中的错误。 So now you end up copying the error handling code from the first controller & pasting it in the rest of the 4 controllers. 所以现在你最终从第一个控制器复制错误处理代码并将其粘贴到4个控制器的其余部分中。

Now the fun starts. 现在开始有趣了。 Imagine that you want to change your logic in the error state. 想象一下,您想要在错误状态下更改逻辑。 Maybe you want to just log the error in console, or show a toaster message perhaps. 也许您只想在控制台中记录错误,或者显示烤箱消息。 So you go to the first controller & update the code. 所以你去第一个控制器并更新代码。 You think you are done? 你认为你完成了吗? NO!!! 没有!!! There are 4 other controllers that are showing the alert message (remember that you pasted the code from the first controller previously???). 有4个其他控制器显示警报消息(请记住,您之前粘贴了第一个控制器的代码???)。 So now, you try to update the rest of the controllers by pasting the new error message logic. 所以现在,您尝试通过粘贴新的错误消息逻辑来更新其余控制器。 Think about all the controllers that you need to update, if you have more!!! 想想你需要更新的所有控制器,如果你有更多! Tiring, isn't it??? 累了,不是吗???

Why to resolve promise in Factory: 为什么在工厂解决承诺:

Now let's say that you write your error handling logic in your service and all the controllers are using this service. 现在假设您在服务中编写了错误处理逻辑,并且所有控制器都在使用此服务。 You have written code to show an alert in case of a promise that fails in this service. 如果承诺在此服务中失败,您已编写代码以显示警报。 All controllers will now start showing this alert, in case of a broken promise. 如果承诺损坏,所有控制器现在将开始显示此警报。 In future, if you wish to update your error logic, you simply update this error logic in your service & all your controllers will start using this updated logic automatically, without any more effort on your part. 将来,如果您希望更新错误逻辑,只需在服务中更新此错误逻辑,所有控制器将自动开始使用此更新逻辑,而无需您付出更多努力。 This way, you have saved yourself tons of time. 这样,你节省了大量的时间。

So think about this: 所以想想这个:

1 change in Factory vs 1 change in all Controllers (which maybe 1 or more) 所有控制器中的1个工厂变化与1个变化(可能是1个或更多)

I would definitely vouch for 1 change in Factory as that helps reuse my logic with just a simple change and only once. 我肯定会保证在Factory中进行1次更改,因为这有助于仅使用一次简单的更改重用我的逻辑。 All my controllers will start using the new logic. 我的所有控制器都将开始使用新逻辑。 Controllers are supposed to be slim, lean & clean. 控制器应该是纤薄,精益和清洁。 Factories & Services are supposed to be reusable. 工厂和服务应该是可重复使用的。 For this reason of reusability, I strongly suggest you handle promise in Factory/Service . 出于这个可重用性的原因,我强烈建议您在工厂/服务中处理承诺

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM