服务应该公开它们的异步性吗? [英] Should services expose their asynchronicity?
问题描述
我正在编写一个异步检索数据的服务($http 或 $resource).我可以通过返回一个最初为空但最终会填充的数组来隐藏它是异步的事实:
I'm writing a service that will retrieve data asynchronously ($http or $resource). I can hide the fact that it is asynchronous by returning an array that will initially be empty, but that will eventually get populated:
.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 来暴露异步性:
Or I can expose the asynchronicity by returning a 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 - 如果有人想尝试上述两种实现.)
(Plunker - if someone wants to play around with the above two implementations.)
公开异步性的一个潜在优势是,我可以通过向 then()
方法添加错误处理程序来处理控制器中的错误.但是,我可能会在应用程序范围的 拦截器.
One potential advantage of exposing the asychronicity would be that I can deal with errors in the controller by adding an error handler to the then()
method. However, I'll likely be catching and dealing with $http errors in an application-wide interceptor.
那么,什么时候应该暴露服务的异步性?
So, when should a service's asynchronicity be exposed?
推荐答案
我猜你会在围栏的两边找到人.就个人而言,我觉得你应该总是暴露一个库或函数的异步性(或者更准确地说:我觉得你应该永远不要隐藏一个库或函数的异步性).主要原因是透明度;例如,这行得通吗?
My guess is that you'll find people on both sides of this fence. Personally, I feel that you should always expose the asynchronicity of a library or function (or more correctly: I feel that you should never hide the asynchronicity of a library or function). The main reason is transparency; for example, will this work?
app.controller('MyController', function(NewsfeedService) {
$scope.posts = NewsfeedService.posts();
doSomethingWithPosts($scope.posts); // <-- will this work?
});
如果您使用第一种方法(例如 $resource
),它不会,即使 $scope.posts
在技术上是一个数组.如果 doSomethingWithPosts
有自己的异步操作,你可能会遇到竞争条件.相反,您无论如何都必须使用异步代码:
If you're using the first method (e.g. $resource
), it won't, even though $scope.posts
is technically an array. If doSomethingWithPosts
has its own asynchronous operations, you could end up with a race condition. Instead, you have to use asynchronous code anyway:
app.controller('MyController', function(NewsfeedService) {
$scope.posts = NewsfeedService.posts(function() {
doSomethingWithPosts($scope.posts);
});
});
(当然,您可以让回调接受posts
作为参数,但我仍然认为它令人困惑且不标准.)
(Of course, you can make the callback accept the posts
as an argument, but I still think it's confusing and non-standard.)
幸运的是,我们有承诺,承诺的真正目的是代表操作的未来价值.此外,由于使用 Angular 的 $q
库创建的 Promise 可以绑定到视图,因此没有任何问题:
Luckily, we have promises, and the very purpose of a promise is to represent the future value of an operation. Furthermore, since promises created with Angular's $q
libraries can be bound to views, there's nothing wrong with this:
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.
});
[更新:您不能再将承诺直接绑定到视图;您必须等待承诺得到解决并手动分配范围属性.]
[Update: you can no longer bind promises directly to the view; you must wait for the promise to be resolved and assign a scope property manually.]
顺便说一句,Restangular,$resource
的流行替代品,使用 promise,AngularJS 自己的 $resource
将在 1.2 中支持它们(他们可能已经在最新的 1.1.x 中支持它们).
As an aside, Restangular, a popular alternative to $resource
, uses promises, and AngularJS' own $resource
will be supporting them in 1.2 (they may already support them in the latest 1.1.x's).
这篇关于服务应该公开它们的异步性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!