我想知道是否可以进行使用$http
的服务调用,以便直接返回数据而不返回承诺?我试图使用$q
而没有任何运气推迟。
这就是我的意思:
我有服务:
angular.module('myModule').factor('myService', ['$http', '$q',
function($http, $q) {
// Public API
return {
myServiceCall: function() {
return $http.get('/server/call');
}
};
}
]);
这就是我所说的:
// My controller:
myService.myServiceCall().then(function(data) {
$scope.data = data;
});
我想避免这种情况,而是希望:
$scope.data = myService.myServiceCall();
我希望它在那条线上完全解决,是否可能?
我尝试过$ q,defer和'然后'的一些组合。方法但似乎无法正确使用,因为该方法立即返回。
修改
如果你想知道为什么,主要的原因是我想简化控制器代码,这很容易用ngResource完成,因为这些调用会在模板中自动解决,所以我想避免做整个& #39;。然后'每次。
并非我不喜欢异步性质,我们的大多数代码都使用它,它只是在一些情况下,同步方式是有帮助的。
我认为,就像你们中的一些人已经指出的那样,我将使用$ resource来获得足够接近的解决方案。
答案 0 :(得分:9)
我可以通过两种方式来做到这一点。第一个肯定比第二个好。
resolve
属性您可以使用路由配置对象的resolve
属性来指定必须解析promise并将解析后的值用于其中一个控制器依赖项的值,以便控制器运行时尽快,价值立即可用。
例如,假设您有以下服务:
app.service('things', ['$http', '$q', function ($http, $q) {
var deferred = $q.defer();
$http({
method: 'GET',
url: '/things',
cache: true
}).success(function (data) {
deferred.resolve(data);
}).error(function (msg) {
deferred.reject(msg);
});
return deferred.promise;
}]);
然后你可以定义你的路线:
$routeProvider.when('/things', {
controller: ['$scope', 'thingsData', function ($scope, thingsData) {
$scope.allThings = thingsData;
}],
resolve: {
thingsData: ['things', function (things) {
return things;
}]
}
});
resolve
对象中的键对应于控制器的第二个依赖项的名称,因此即使它返回一个promise,也会在控制器运行之前解析该promise。
第二种方式,一点都不理想,并且可能会在某些时候咬你的屁股,就是尽早提出数据请求,例如当你的应用程序初始化时,然后实际得到稍后的数据,比如在需要3次点击的页面上从主页进入。手指交叉,如果星星已对齐,那么您的http请求将在此时返回,您将拥有要使用的数据。
angular.module('myModule').factory('myService', ['$http', '$q', function($http, $q) {
var data = [];
function fetch() {
$http.get('/server/call').then(function (d) { data = d; });
}
// Public API
return {
fetchData: fetch,
myServiceCall: function () {
return data;
}
};
}]);
然后,在模块的运行功能中,发出请求:
angular.module('myModule').run(['myService', function (myService) {
myService.fetchData();
});
然后,在应用程序启动后保证至少运行3秒的页面控制器中,您可以按照建议执行操作:
angular.module('myModule').controller('deepPageCtrl', ['$scope', 'myService', function ($scope, myService) {
$scope.data = myService.myServiceCall();
if (angular.isArray($scope.data) && $scope.data.length === 0) {
panic("data isn't loaded yet");
}
}]);
按照ricick的建议,并使用jQuery的.ajax()
方法使用同步AJAX请求。
答案 1 :(得分:2)
这是不可能的,因为http调用本质上是异步的。也就是说,您需要等待服务器响应。
$ resource服务通过返回一个代理对象来解决这个问题,该代理对象填充了服务器响应中返回的数据,但它仍未在一行中完全解析。
修改强>
实际上可以使用jquery ajax方法创建同步http请求,方法是设置" async"选项为false。
您可以创建一个包装它的服务,但是您的应用程序将会锁定"当请求等待服务器响应时,因此对于大多数情况,这将是不好的做法。此类请求还有其他限制。
有关更多详细信息,请参阅文档:
答案 2 :(得分:0)
很久以前(在有角度的土地上,实际上是在去年的某个时候),它实际上是如何运作的。
但是现在情况已经不再如此了,我认为这是由于视图和控制器中承诺的行为差异,更多的是关于弃用: Angularjs promise not binding to template in 1.2