在我的应用程序中,我有一系列的诺言作为功能。我的每个服务函数都返回一个deferred.promise
;
考虑到以下情况,我有一个主要的getUser服务异步调用getUserPreferences和getUserFavourites的问题,解决了getUserData之后的console.log在getUserFavourites响应之前就已经解决了!一旦getUserFavourites响应,是否应该解决getUserData中的承诺?
实际上,从控制台“获取所有用户数据”。在调用getUserFavourites之前,日志位于控制台中。从字面上看,在getUser响应之后,几乎就像getUserData().then(
一样,它只能解决顶级承诺并使底层2异步...
我在这里做什么错了?
var user = 'blabla';
function getUserData() {
var deferred = $q.defer();
getUser(user).then(
function(response) {
getUserPreferences(response.user).then(
function(preferences) {
console.log('preferences', preferences);
},
function() {
deferred.reject();
}
);
getUserFavourites(response.user).then(
function(favourites) {
deferred.resolve();
console.log('favourites', favourites);
},
function() {
deferred.reject();
}
);
},
function() {
deferred.reject();
}
);
return deferred.promise;
}
getUserData().then(
function() {
console.log('got all user data');
}
);
答案 0 :(得分:0)
您必须返回嵌套的promise才能拥有链。
这里的问题是您有2个嵌套的Promise,因此您需要返回一个Promise.all(或您的情况下的$ q.all),并接受getUserPreferences
和getUserFavorites
返回的2个Promise的数组:
var user = 'blabla';
function getUserPreferences(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({color: 'green'});
},500);
});
}
function getUserFavorites(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve([{id: 1, title: 'first favorite'}, {id: 2, title: 'second favorite'}]);
},500);
});
}
function getUser(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(user);
},500);
});
}
function getUserData() {
return getUser().then(
function(user) {
console.log(user);
var prefPromise = getUserPreferences(user).then(
function(preferences) {
console.log('preferences', preferences);
return preferences;
},
function(error) {
console.log("Error getting preferences");
throw error;
}
);
var favPromise = getUserFavorites(user).then(
function(favourites) {
console.log('favourites', favourites);
return favourites;
},
function(error) {
console.log("Error getting favorites");
throw error;
}
);
return Promise.all([
prefPromise,
favPromise
]);
},
function(err) {
console.log("Error getting user");
throw err;
}
);
}
getUserData().then(
function(results) {
console.log(results);
}
);
请注意,出于演示目的,我使用的是es6 Promise而不是有角$ q,但实质是相同的:
$q.defer() => new Promise()
$q.all => Promise.all
由于Promise模式非常适合简化异步代码并使它看起来像同步代码,因此您可以使用以下方法简化上层示例:
var user = { name: 'blabla'};
function getUserPreferences(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({color: 'green'});
},500);
});
}
function getUserFavorites(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve([{id: 1, title: 'first favorite'}, {id: 2, title: 'second favorite'}]);
},500);
});
}
function getUser(){
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(user);
},500);
});
}
function getUserData() {
return getUser()
.then(user => { // user is resolved
// running parallel promises to get user infos:
return Promise.all([
user,
getUserPreferences(user),
getUserFavorites(user)
]);
})
.then(results => {
// wrapping the results into something more semantic:
let userData = results[0];
userData.prefs = results[1];
userData.favs = results[2];
return userData;
});
}
getUserData().then(
function(userData) {
console.log('Final result:');
console.log(userData);
}
);
答案 1 :(得分:0)
一种修复方法是使用async/await
使代码看起来同步。
var user = 'blabla';
async function getUserData() {
try {
var deferred = $q.defer();
let userInfo = await getUser(user)
let userPrefs = await getUserPreferences(userInfo.user)
console.log('preferences', userPrefs);
let userFavourites = await getUserFavourites(userInfo.user)
deferred.resolve();
console.log('favourites', userFavourites);
return deferred.promise;
} catch (error) {
deferred.reject();
}
}
getUserData().then(
function() {
console.log('got all user data');
}
);
答案 2 :(得分:0)
使用$q.all
返回复合承诺:
function getUserData() {
return getUser(user).then(function(response) {
var preferencesPromise = getUserPreferences(response.user);
var favouritesPromise = getUserFavourites(response.user);
return $q.all([preferencesPromise, favouritesPromise]);
});
}
然后从复合承诺中提取数据:
getUserData().then([preferences, favourites] => {
console.log('got all user data');
console.log(preferences, favourites);
}).catch(function(error) {
console.log(error);
});
$q.all
方法返回一个单个promise,将使用值的数组/哈希值对其进行解析,每个值对应于promise数组/哈希中相同索引/键处的promise。如果任何一个承诺都被拒绝解决,则此产生的承诺将以相同的拒绝值被拒绝。
有关更多信息,请参见