$q.defer() 不适用于 Angular 服务
$q.defer() not working with Angular service
我是 angular 的 $q 的新手,我正在尝试构建一个服务来进行 API 调用并将其 returns 返回给控制器。
问题:无论我如何格式化它,服务 returns
就在它到达 $http.get(...)
之前
服务:
// 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;
}
控制器
$scope.recentActivity = activityService.getFeed(profile);
// also tried
activityService.getFeed(profile).then(function (res) {
$scope.recentActivity = res;
console.log(res);
});
编辑:9:40am 2015 年 5 月 6 日
如果可能,我想从服务中检索控制器中的 activity 列表,就像它是新的一样(使用 .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.
}
我认为如果您想拥有响应对象,则需要使用 .success 而不是 .then。
$http.get(url, {
params: {
"following": JSON.stringify(following)
}
})
.success(function(res) {
console.log(res);
deferred.resolve(res.data);
});
在了解了@New Dev 在评论中指出的 deferred anti-pattern 之后,我编辑了这个答案。详细解释请看@New Dev 的回答。感谢@New Dev.
服务
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);
});
}
}
控制器
activityService
.getFeed(profile)
.then(function (activities) {
$scope.recentActivity = activities;
});
没有必要使用 $q.defer
除非你将带有回调的非基于承诺的 API 转换为基于承诺的 API (即便如此,它也是建议使用 $q(function(resolve, reject){...})
)。
$http
已经 return 是一个承诺 - 只是 return 那个 (或链式 .then
承诺);
var httpResponsePromise = $http.get(url); // returns a promise
var actualDataPromise = httpResponsePromise.then(function(resp){ return resp.data; });
return actualDataPromise;
或更短(和典型):
return $http.get(url).then(function(response){
return response.data;
});
其次,承诺-returning API return承诺 - 而不是结果 - 立即,同步。您需要 .then
才能得到结果。
最后,一旦 API 是异步的,它就应该始终是异步的 - 不要将其转换为同步或有时同步的 API。因此,在任何地方,一直到数据的最终接收者,您都需要使用 .then
处理程序。
因此,您的服务 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;
}
控制器中的用法与任何其他基于 promise 的用法一样 API:
activityService.getFeed(profile)
.then(function(activities) {
$scope.recentActivity = activities;
});
我是 angular 的 $q 的新手,我正在尝试构建一个服务来进行 API 调用并将其 returns 返回给控制器。
问题:无论我如何格式化它,服务 returns
就在它到达 $http.get(...)
服务:
// 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;
}
控制器
$scope.recentActivity = activityService.getFeed(profile);
// also tried
activityService.getFeed(profile).then(function (res) {
$scope.recentActivity = res;
console.log(res);
});
编辑:9:40am 2015 年 5 月 6 日
如果可能,我想从服务中检索控制器中的 activity 列表,就像它是新的一样(使用 .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.
}
我认为如果您想拥有响应对象,则需要使用 .success 而不是 .then。
$http.get(url, {
params: {
"following": JSON.stringify(following)
}
})
.success(function(res) {
console.log(res);
deferred.resolve(res.data);
});
在了解了@New Dev 在评论中指出的 deferred anti-pattern 之后,我编辑了这个答案。详细解释请看@New Dev 的回答。感谢@New Dev.
服务
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);
});
}
}
控制器
activityService
.getFeed(profile)
.then(function (activities) {
$scope.recentActivity = activities;
});
没有必要使用 $q.defer
除非你将带有回调的非基于承诺的 API 转换为基于承诺的 API (即便如此,它也是建议使用 $q(function(resolve, reject){...})
)。
$http
已经 return 是一个承诺 - 只是 return 那个 (或链式 .then
承诺);
var httpResponsePromise = $http.get(url); // returns a promise
var actualDataPromise = httpResponsePromise.then(function(resp){ return resp.data; });
return actualDataPromise;
或更短(和典型):
return $http.get(url).then(function(response){
return response.data;
});
其次,承诺-returning API return承诺 - 而不是结果 - 立即,同步。您需要 .then
才能得到结果。
最后,一旦 API 是异步的,它就应该始终是异步的 - 不要将其转换为同步或有时同步的 API。因此,在任何地方,一直到数据的最终接收者,您都需要使用 .then
处理程序。
因此,您的服务 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;
}
控制器中的用法与任何其他基于 promise 的用法一样 API:
activityService.getFeed(profile)
.then(function(activities) {
$scope.recentActivity = activities;
});