I'm new to angular's $q and I'm trying to build a service that makes an API call and returns it back to the controller.
我是angular的$ q的新手,我正在尝试构建一个API调用服务并将其返回给控制器。
Problem: No matter how I seem to format it, the service returns
right before it gets to $http.get(...)
问题:无论我如何格式化它,服务都会在它到达$ http.get(...)之前返回
Service:
服务:
// methods: query new, get existing
makeRequest: function(url, following) {
// create promise
var deferred = $q.defer();
$http.get(url, {
params: {
"following": JSON.stringify(following)
}
})
.then(function(res) {
console.log(res);
deferred.resolve(res.data);
});
return deferred.promise;
},
getFeed: function(user) {
console.log('>> userService[getUser]: retrieving user...');
if (!this.activities) {
// Request has not been made, setting user profile.
console.log('>> userService[getUser]: No user stored, making request...');
var following = this.compileArray(user);
console.log(following);
this.activities = this.makeRequest('api/network/activities', following);
};
// Return the myObject stored on the service
return this.activities;
}
Controller
调节器
$scope.recentActivity = activityService.getFeed(profile);
// also tried
activityService.getFeed(profile).then(function (res) {
$scope.recentActivity = res;
console.log(res);
});
EDIT : 9:40am 05/06/2015
编辑:上午9:40 05/06/2015
If possible, I'd like to retrieve the activity list in the controller from the service in the same way I would if it were new (using .then
). Is that possible/ bad practice?
如果可能的话,我想从服务中检索控制器中的活动列表,就像它是新的一样(使用.then)。这是可能/不好的做法吗?
getFeed: function(user) {
if (!this.activities) {
...
} else {
feedPromise = $q(function(resolve){ resolve(this.activities) });
console.log(feedPromise);
// returns: {$$state: Object, then: function, catch: function, finally: function}
feedPromise.then(function(res) {
console.log(res);
// returns: undefined
});
console.log(that.activities);
// Works, returns list of activities.
}
3 个解决方案
#1
5
There is no need to use a $q.defer
unless you are converting a non-promise based API with callbacks into a promise-based API (and even then, it is recommended to use $q(function(resolve, reject){...})
).
除非您将带有回调的基于非承诺的API转换为基于承诺的API,否则无需使用$ q.defer(即使这样,建议使用$ q(函数(解析,拒绝){。 ..}))。
$http
already returns a promise - just return that (or a chained .then
promise);
$ http已经返回一个承诺 - 只返回那个(或链接的.then承诺);
var httpResponsePromise = $http.get(url); // returns a promise
var actualDataPromise = httpResponsePromise.then(function(resp){ return resp.data; });
return actualDataPromise;
or shorter (and typical):
或更短(和典型):
return $http.get(url).then(function(response){
return response.data;
});
Second, a promise-returning API returns the promise - not the result - right away, synchronously. You need a .then
to get the result.
其次,承诺返回API会立即同步返回承诺 - 而不是结果。你需要一个.then才能得到结果。
Lastly, once an API is async, it should always be async - don't convert it to a sync or a sometimes-sync API. So, everywhere, all the way to the end recipient of the data, you need to use a .then
handler.
最后,一旦API是异步的,它应始终是异步的 - 不要将其转换为同步或有时同步API。因此,无论在哪里,一直到数据的最终接收者,您都需要使用.then处理程序。
So, your service API can be made quite simple:
因此,您的服务API可以非常简单:
makeRequest: function(url, following){
return $http.get(url, {params: { "following": following }})
.then(function(response){
return response.data;
});
},
getFeed: function(user) {
var that = this;
var feedPromise;
if (!that.activities) {
var following = this.compileArray(user);
feedPromise = this.makeRequest('api/network/activities', following)
.then(function(activities){
that.activities = activities;
return activities;
});
} else {
feedPromise = $q(function(resolve){ resolve(that.activities); });
// or you could have cached the old feedPromise and returned that
}
return feedPromise;
}
The usage in the controller is just like with any other promise-based API:
控制器中的用法与任何其他基于promise的API一样:
activityService.getFeed(profile)
.then(function(activities) {
$scope.recentActivity = activities;
});
#2
0
After learning about the deferred anti-pattern as pointed out in the comments by @New Dev, I have edited this answer. Please see @New Dev's answer for a detailed explanation. Thanks @New Dev.
在了解@New Dev的评论中指出的延迟反模式后,我编辑了这个答案。有关详细说明,请参阅@New Dev的答案。谢谢@New Dev。
Service
服务
makeRequest: function(url, following) {
return $http.get(url, {
params: {
"following": JSON.stringify(following)
}
}).then(function(res) {
return res.data;
});
},
getFeed: function(user) {
var that = this;
if (!that.activities) {
var following = that.compileArray(user);
return that.makeRequest('api/network/activities', following)
.then(function(activities){
that.activities = activities;
return that.activities;
});
} else {
return $q(function(resolve) {
resolve(that.activities);
});
}
}
Controller
调节器
activityService
.getFeed(profile)
.then(function (activities) {
$scope.recentActivity = activities;
});
#3
-1
i think you need to use .success instead of .then if you want to have the response object.
我认为如果你想拥有响应对象,你需要使用.success而不是.then。
$http.get(url, {
params: {
"following": JSON.stringify(following)
}
})
.success(function(res) {
console.log(res);
deferred.resolve(res.data);
});
#1
5
There is no need to use a $q.defer
unless you are converting a non-promise based API with callbacks into a promise-based API (and even then, it is recommended to use $q(function(resolve, reject){...})
).
除非您将带有回调的基于非承诺的API转换为基于承诺的API,否则无需使用$ q.defer(即使这样,建议使用$ q(函数(解析,拒绝){。 ..}))。
$http
already returns a promise - just return that (or a chained .then
promise);
$ http已经返回一个承诺 - 只返回那个(或链接的.then承诺);
var httpResponsePromise = $http.get(url); // returns a promise
var actualDataPromise = httpResponsePromise.then(function(resp){ return resp.data; });
return actualDataPromise;
or shorter (and typical):
或更短(和典型):
return $http.get(url).then(function(response){
return response.data;
});
Second, a promise-returning API returns the promise - not the result - right away, synchronously. You need a .then
to get the result.
其次,承诺返回API会立即同步返回承诺 - 而不是结果。你需要一个.then才能得到结果。
Lastly, once an API is async, it should always be async - don't convert it to a sync or a sometimes-sync API. So, everywhere, all the way to the end recipient of the data, you need to use a .then
handler.
最后,一旦API是异步的,它应始终是异步的 - 不要将其转换为同步或有时同步API。因此,无论在哪里,一直到数据的最终接收者,您都需要使用.then处理程序。
So, your service API can be made quite simple:
因此,您的服务API可以非常简单:
makeRequest: function(url, following){
return $http.get(url, {params: { "following": following }})
.then(function(response){
return response.data;
});
},
getFeed: function(user) {
var that = this;
var feedPromise;
if (!that.activities) {
var following = this.compileArray(user);
feedPromise = this.makeRequest('api/network/activities', following)
.then(function(activities){
that.activities = activities;
return activities;
});
} else {
feedPromise = $q(function(resolve){ resolve(that.activities); });
// or you could have cached the old feedPromise and returned that
}
return feedPromise;
}
The usage in the controller is just like with any other promise-based API:
控制器中的用法与任何其他基于promise的API一样:
activityService.getFeed(profile)
.then(function(activities) {
$scope.recentActivity = activities;
});
#2
0
After learning about the deferred anti-pattern as pointed out in the comments by @New Dev, I have edited this answer. Please see @New Dev's answer for a detailed explanation. Thanks @New Dev.
在了解@New Dev的评论中指出的延迟反模式后,我编辑了这个答案。有关详细说明,请参阅@New Dev的答案。谢谢@New Dev。
Service
服务
makeRequest: function(url, following) {
return $http.get(url, {
params: {
"following": JSON.stringify(following)
}
}).then(function(res) {
return res.data;
});
},
getFeed: function(user) {
var that = this;
if (!that.activities) {
var following = that.compileArray(user);
return that.makeRequest('api/network/activities', following)
.then(function(activities){
that.activities = activities;
return that.activities;
});
} else {
return $q(function(resolve) {
resolve(that.activities);
});
}
}
Controller
调节器
activityService
.getFeed(profile)
.then(function (activities) {
$scope.recentActivity = activities;
});
#3
-1
i think you need to use .success instead of .then if you want to have the response object.
我认为如果你想拥有响应对象,你需要使用.success而不是.then。
$http.get(url, {
params: {
"following": JSON.stringify(following)
}
})
.success(function(res) {
console.log(res);
deferred.resolve(res.data);
});