[英]Promise resolved before entire chain of promises is resolved
我的应用程序中有一系列承诺作为函数。 我的每个服务函数都返回一个deferred.promise
;
考虑到以下场景,我的主要 getUser 服务异步调用 getUserPreferences 和 getUserFavourites,解析 getUserData 后的 console.log 在 getUserFavourites 甚至响应之前就被解析了! 一旦 getUserFavourites 响应,不应该解决 getUserData 中的承诺吗?
实际上,在调用 getUserFavourites 之前, console.log 中的“获取所有用户数据”已在控制台中。 在 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');
}
);
您必须返回嵌套的承诺才能拥有链。 这里的问题是你有 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 而不是 angular $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); } );
一种解决方法是使用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');
}
);
使用$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 数组/散列中相同索引/键处的promise。 如果任何承诺被拒绝解决,这个结果承诺将被拒绝以相同的拒绝值。
有关更多信息,请参阅
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.