为什么要将$ http调用移动到服务中?

时间:2016-06-04 11:50:20

标签: javascript angularjs

目前我在三个控制器上都有这样的电话:

$scope.getCurrentUser = function () {
    $http.post("/Account/CurrentUser", {}, postOptions)
        .then(function(data) {
                var result = angular.fromJson(data.data);
                if (result != null) {
                    $scope.currentUser = result.id;
                }
            },
            function(data) {
                alert("Browser failed to get current user.");
            });
};

我看到很多建议将$http调用封装到HttpService或其他类似的东西中,但是返回promise比返回数据要好得多。然而,如果我返回承诺,我的控制器$http中除了一行之外的所有行都会调用更改,并且处理响应的所有逻辑都保留在我的控制器中,例如:

$scope.getCurrentUser = function() {
    RestService.post("/Account/CurrentUser", {}, postOptions)
        .then(function(data) {
                var result = angular.fromJson(data.data);
                if (result != null) {
                    $scope.currentUser = result.id;
                }
            },
            function(data) {
                alert("Browser failed to get current user.");
            });
};

我可以为每个服务器端控制器创建一个RestService,但这最终只能调用核心服务并传递URL。

4 个答案:

答案 0 :(得分:2)

控制器执行表示逻辑(它在Angular Model-View-Whatever模式中充当视图模型)。服务做业务逻辑(模型)。这是经过战争验证的关注点分离和OOP良好实践的固有部分。

精简控制器和胖服务可确保应用程序单元保持可重用,可测试和可维护。

如果将$http替换为RestService,如果它们是相同的,则没有任何好处。业务和表示逻辑的正确分离应该是这样的

$scope.getCurrentUser = function() {
  return UserService.getCurrent()
  .then(function(user) {
    $scope.currentUser = user.id;
  })
  .catch(function(err) {
    alert("Browser failed to get current user.");
    throw err;
  });
});

它负责结果调节并返回一个承诺。 getCurrentUser传递一个promise,因此可以根据需要链接(通过其他控制器方法或测试)。

答案 1 :(得分:2)

有几个原因可以解释为什么它是非平凡应用程序的良好实践。

使用单个通用服务并传入url和参数并不会增加您注意到的价值。相反,您需要为每种类型的提取设置一种方法。

使用服务的一些好处:

  • <强>重新使用性即可。在一个简单的应用程序中,每个控制器可能有一个数据提取。但这很快就会改变。例如,您可能有一个包含getProducts的产品列表页面和一个包含getProductDetail的详细信息页面。但是,您希望在详细信息页面上添加销售页面,类别页面或显示相关产品。这些可能都使用原始的getProducts(带有适当的参数)。
  • 测试即可。您希望能够独立于外部数据源测试控制器。将数据提取到控制器并不容易。使用服务,您只需模拟服务,就可以使用稳定的已知数据测试控制器。
  • 可维护性即可。您可以决定使用简单的服务,即使您正在重复使用它,也只需将所有代码放在控制器中即可。如果后端路径发生变化会发生什么?现在你需要在它使用的任何地方更新它。如果需要一些额外的逻辑来处理数据,或者你需要通过另一个调用获得一些补充数据,会发生什么?通过服务,您可以在一个地方进行更改。随着它进入控制器,你还有更多的工作要做。
  • 代码清晰度。您希望您的方法能够做出清晰,具体的事情。控制器负责围绕应用程序特定部分的逻辑。添加获取数据的机制会让人感到困惑。通过一个简单的例子,您需要的唯一额外逻辑是解码json。如果您的后端以完全正确的格式准确地返回控制器所需的数据,那就不错了,但情况可能并非如此。通过拆分代码,每个方法都可以做好一件事。让服务获取数据并以完全正确的格式将其传递给控制器​​,然后让控制器执行此操作。

答案 2 :(得分:0)

让您的服务看起来像这样:

app.factory('AccountService', function($http) {
    return {
        getCurrentUser: function(param1, param2) {
            var postOptions = {}; // build the postOptions based on params here
            return $http.post("/Account/CurrentUser", {}, postOptions)
            .then(function(response) {
              // do some common processing here
            });
        }
    };
});

然后调用此方法将是这样的:

$scope.getCurrentUser = function() {
    AccountService.getCurrentUser(param1, param2)
    .then(function(currentUser){
        // do your stuff here
    });
};

它看起来更好,可以避免在多个控制器中重复后端服务URL和postOptions变量构造。

答案 3 :(得分:0)

简单。将每个函数写为服务,以便您可以重用它。由于这是一个异步调用,因此使用角度承诺通过将数据包装在promise中来将数据发送回控制器。