angularjs - 服务应该暴露它们的异步性吗?

标签 angularjs angularjs-service

我正在编写一个将异步检索数据的服务($http 或 $resource)。我可以通过返回一个最初为空但最终会被填充的数组来隐藏它是异步的事实:

.factory('NewsfeedService1', ['$http', function($http) {
   var posts = [];
   var server_queried = false;
   return {
      posts: function() {
         if(!server_queried) {
            $http.get('json1.txt').success(
              function(data) {
                server_queried = true;
                angular.copy(data, posts);
            });
         }
         return posts;
      }
   };
}])
.controller('Ctrl1', ['$scope','NewsfeedService1',
function($scope, NewsfeedService1) {
    $scope.posts = NewsfeedService1.posts();
}])

或者我可以通过返回一个 promise 来暴露异步性:

.factory('NewsfeedService2', ['$http', function($http) {
  var posts = [];
  var server_queried = false;
  var promise;
  return {
     posts_async: function() {
       if(!promise || !server_queried) {
         promise = $http.get('json2.txt').then(
           function(response) {
              server_queried = true;
              posts = response.data;
              return posts;
         });
       }
       return promise;
     }
  };
}])

.controller('Ctrl2', ['$scope','NewsfeedService2',
function($scope, NewsfeedService2) {
  NewsfeedService2.posts_async().then(
    function(posts) {
      $scope.posts = posts;
  });
  // or take advantage of the fact that $q promises are
  // recognized by Angular's templating engine:
  // (note that Peter and Pawel's AngularJS book recommends against this, p. 100)
  $scope.posts2 = NewsfeedService2.posts_async();
}]);

(Plunker - 如果有人想玩弄上述两种实现。)

暴露异步性的一个潜在优势是我可以通过向 then() 添加错误处理程序来处理 Controller 中的错误。方法。但是,我可能会在应用程序范围内捕获和处理 $http 错误 interceptor .

那么,什么时候应该暴露服务的异步性呢?

最佳答案

我的猜测是你会在这道栅栏的两边找到人。就个人而言,我认为您应该始终公开库或函数的异步性(或者更准确地说:我认为您永远不应该隐藏库或函数的异步性)。主要原因是透明度;例如,这行得通吗?

app.controller('MyController', function(NewsfeedService) {
  $scope.posts = NewsfeedService.posts();
  doSomethingWithPosts($scope.posts); // <-- will this work?
});

如果您使用第一种方法(例如 $resource ),则不会,即使 $scope.posts在技​​术上是一个数组。如果 doSomethingWithPosts有它自己的异步操作,你最终可能会遇到竞争条件。相反,无论如何您都必须使用异步代码:

app.controller('MyController', function(NewsfeedService) {
  $scope.posts = NewsfeedService.posts(function() {
    doSomethingWithPosts($scope.posts);
  });
});

(当然,您可以让回调接受 posts 作为参数,但我仍然认为它令人困惑且不标准。)

幸运的是,我们有 Promise,而 Promise 的目的就是代表操作的 future 值(value)。此外,由于使用 Angular 的 $q 创建的 Promise库可以绑定(bind)到 View ,这没有错:

app.controller('MyController', function(NewsfeedService) {
  $scope.posts = NewsfeedService.posts();
  // $scope.posts is a promise, but when it resolves
  // the AngularJS view will work as intended.
});

[更新:您不能再将 Promise 直接绑定(bind)到 View ;您必须等待 promise 得到解决并手动分配范围属性。]

顺便说一句,Restangular$resource 的流行替代品, 使用 Promise 和 AngularJS 自己的 $resource将在 1.2 中支持它们(他们可能已经在最新的 1.1.x 中支持它们)。

关于angularjs - 服务应该暴露它们的异步性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17416599/

相关文章:

javascript - AngularJS 中的切换复选框未反射(reflect)在 Controller 中

javascript - Angularjs ng-repeat 使用键作为对象的属性名称

javascript - 无法删除 ui-gmap-google-map 中的选定多边形

javascript - Controller 连接到指令进行验证

javascript - 如何获取使用循环内的 ng-options 实现的选择框的值?

javascript - 在 Angular 中的 Controller 之间共享数据,观看还是不观看?

javascript - AngularJS 1.2.19 从嵌套 $resource 服务返回值

angularjs - 我怎样才能在 AngularJS 中写一个 promise

javascript - angularjs - 将公共(public)属性从一个对象复制到另一个对象

javascript - 如何将 $stateParams 从 ui-router 传递到 resolve 服务?