簡體   English   中英

承諾在整個承諾鏈解決之前解決

[英]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 在你的情況下)獲取getUserPreferencesgetUserFavorites返回的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM