如何制作Angular服务代码"看起来是同步的"?
当我清理控制器并将业务逻辑代码放入服务中时,我的问题出现了。到现在为止还挺好。现在我想等待"在服务函数中,直到所有异步调用都返回并且然后返回。我怎么能这样做?
为了说明我的问题,假设你有一个只有的控制器代码:
就像那样:
重构前的DataController:
$scope.submitForm = function() {
RestBackend.query('something').then(function(data) {
// do some additional things ...
...
$scope.data = data;
});
};
非常简单。获取数据并填充范围。
在重构为控制器+服务之后,我最终得到了:
DataController重构:
$scope.submitForm = function() {
DataService.getData().then(function(data) {
$scope.data = data;
});
};
DataService重构:
this.query = function() {
var dataDefer = $q.defer();
RestBackend.query('something').then(function(data) {
// do some additional things ...
...
dataDefer.resolve(data);
});
return dataDefer.promise;
};
我不喜欢我必须在控制器中使用承诺的事实。我喜欢承诺,但我想让控制器不知道这个"实现细节"的服务。这就是我希望控制器代码看起来像:
DataController(应该如此):
$scope.submitForm = function() {
$scope.data = DataService.getData();
};
你明白了吗?在控制器中,我不想关心承诺与否。只需等待获取数据然后使用它。因此,我正在寻找实现这样的服务的可能性:
现在第2项对我来说不清楚:我怎样才能等到数据被提取出来"然后才继续?目标是服务功能看起来是同步的。
答案 0 :(得分:2)
我也认为你的解决方案很好 返回承诺不是服务的实现细节。它是服务API的一部分("合同"服务和服务 - 消费者之间)。
控制器需要一个与数据一起解析的承诺,并根据需要处理它 如何构建承诺,如何获取数据等,这些都是实现细节 您可以随时将服务交换为完全不同的服务,只要它履行合同(即返回一个随数据准备就绪的承诺)。
也就是说,如果您只使用视图中的数据(即在获取后不立即在控制器中直接操作它),这似乎就是这种情况,您可以使用ngResources
方法:< / p>
返回一个空数组,并在获取数据后用数据填充它:
$scope.data = DataService.getData();
// DataService refactored:
this.getData = function () {
var data = [];
RestBackend.query('something').then(function(responseData) {
// do some additional things ...
...
angular.forEach(responseData, function (item) {
data.push(item);
});
});
return data;
};
顺便说一下,在当前(精细)设置中,您需要$q.defer()
。你可以使用promise-chaining:
this.query = function() {
return RestBackend.query('something').then(function(data) {
// do some additional things ...
...
return data;
});
};
答案 1 :(得分:1)
我认为你所拥有的是一个非常好的解决方案。你不应该等待承诺得到解决,它会失去async javascript的目的。只要问问自己为什么需要让它同步运行?
如果你依赖html承诺得到解决,你可以做这样的事情
<div class="alert alert-warning text-center" data-ng-hide="!data.$resolved">
Got data from service.
</div>
答案 2 :(得分:1)
当您使用ngRoute
时,我建议您在路由配置中解析数据,并且一旦所有数据将加载视图得到解决。
$routeProvider
.when('/your-url', {
templateUrl: 'path/to/your/template.html',
controller: 'YourCtrl',
// that's the point !
resolve: {
superAwesomeData: function (DataService) {
return DataService.getData();
}
}
});
现在,superAwesomeData
可以在您的控制器中注入,它将包含已解决的数据。
angular.module('youModule')
.controller('YourCtrl', function (superAwesomeData) {
// superAwesomeData === [...];
});