0

如果可能,我需要一些有關promise的幫助。我是AngularJS的新手,不知道如何處理我遇到的問題。基本上,問題是我有兩個不同的數組,它們是異步初始化的,最終將兩個數據存儲在同一個數組中,並在多個項目的for-loop中執行此操作。我遇到的錯誤是當它加載正確數量的項目時,它顯示所有不同的用戶數據,但不是一個不同的圖片。所顯示的圖片對於每個條目都是相同的。在整個代碼部分的末尾,您會發現:用承諾循環獲取firebase對象

userPromise.then(function(user){ 
     picPromise.then(function(url){ 
      newfriendsinfo.push({ 
       id: newfriendid, 
       name: user.val().name, 
       email: user.val().email, 
       agreed: newfriendagreed, 
       profilepicture: url 
      }); 
     }).then(function(){ 
      if (newfriendsinfo.length == newfriends.length){ 
       deferred.resolve(newfriendsinfo); 
      } 
     }); 
    }); 

我確定這是我的問題所在。它在不使用新圖片的情況下查找新的用戶數據。但是,我不知道我該如何處理這個問題。我研究了多個延遲變量和$ q.all,但我不太明白我應該如何解決這個問題。您可以在下面找到完整的相關代碼。非常感謝您的幫助:)

var friendsRef = firebase.database().ref('friendships/' + firebase.auth().currentUser.uid); 

$scope.friends = $firebaseArray(friendsRef); 

$scope.friendsinfo = []; 

$scope.$watch('friends', function() { 
    var newfriends = $scope.friends; 

    asyncUpdateFriendsInfo(newfriends).then(function(newlist){ 
     $scope.friendsinfo = newlist; 
    }); 
}, true); 

function fetchPicture(ref){ 
    return ref.getDownloadURL().then(function(url) { 
     return url; 
    }).catch(function(error) { 
     alert("error"); 
    }); 
} 

function fetchUserInfo(ref){ 
    return ref.once('value', function(snapshot){ 

    }).then(function(snapshot){ 
     return snapshot; 
    }); 
} 

function asyncUpdateFriendsInfo(newfriends){ 
var deferred = $q.defer(); 
var newfriendsinfo = []; 

for(var i = 0; i < newfriends.length; i++){ 
    var ref = firebase.database().ref('users/' + newfriends[i].$id); 
    var profilePicRef = firebase.storage().ref("profilepictures/" + newfriends[i].$id + "/profilepicture"); 
    var userPromise = fetchUserInfo(ref); 
    var picPromise = fetchPicture(profilePicRef); 

    var newfriendid = newfriends[i].$id; 
    var newfriendagreed = newfriends[i].agreed; 

    userPromise.then(function(user){ 
     picPromise.then(function(url){ 
      newfriendsinfo.push({ 
       id: newfriendid, 
       name: user.val().name, 
       email: user.val().email, 
       agreed: newfriendagreed, 
       profilepicture: url 
      }); 
     }).then(function(){ 
      if (newfriendsinfo.length == newfriends.length){ 
       deferred.resolve(newfriendsinfo); 
      } 
     }); 
    }); 
} 

return deferred.promise; 

}

+2

避免[遞延反模式(HTTP:/ /stackoverflow.com/q/23803743/1048572)! – Bergi

+0

「*'if(newfriendsinfo.length == newfriends.length)'*」是[not going to work](http://stackoverflow.com/a/40032582/1048572)。爲什麼不簡單地使用'$ q.all'? – Bergi

回答

1

的問題肯定是在這個代碼。

userPromise.then(function(user){ 
    picPromise.then(function(url){ 

你有嵌套的承諾,這並不能保證userPromise將首先被解決,picPromise將第二個解決。

它們是兩個獨立的異步調用。如果首先解決picPromise,則永遠不會調用以下代碼。

newfriendsinfo.push({ 
    id: newfriendid, 
    name: user.val().name, 
    email: user.val().email, 
    agreed: newfriendagreed, 
    profilepicture: url 
}); 

除此之外,即使第一userPromise解決,然後picPromise你還是會出現問題。 您正在使用變量newfriendidnewfriendagreed承諾,該承諾在循環承諾之外創建。在這裏你有問題Closures

以下是調用asyncUpdateFriendsInfo函數時會發生的情況。

當循環完成了所有請求將被髮送(但響應尚未收到)和newfriendidnewfriendagreednewfriends的最後一個記錄的$idagreed。所以在newfriendsinfo所有newfriendid將是相同的,將是最後newfriendid

檢查出 「Asynchronous Process inside a javascript for loop

這個問題,如果事實上,你應該將這段代碼

userPromise.then(function(user){ 
    picPromise.then(function(url){ 
     newfriendsinfo.push({ 
      id: newfriendid, 
      name: user.val().name, 
      email: user.val().email, 
      agreed: newfriendagreed, 
      profilepicture: url 
     }); 
    }).then(function(){ 
     if (newfriendsinfo.length == newfriends.length){ 
      deferred.resolve(newfriendsinfo); 
     } 
    }); 
}); 

弄成這個樣子

(function(newfriendid){ 
    var finalUser, 
     finalUrl; 

    userPromise.then(function(user){ 
     finalUser = user; 
     checkIfBothLoaded(); 
    }); 

    picPromise.then(function(url){ 
     finalUrl = url; 
     checkIfBothLoaded(); 
    }); 

    function checkIfBothLoaded(){ 
     if (finalUser && finalUrl){ 
      newfriendsinfo.push({ 
       id: newfriendid, 
       name: finalUser.val().name, 
       email: finalUser.val().email, 
       agreed: newfriendagreed, 
       profilepicture: finalUrl 
      }); 
     } 

     if (newfriendsinfo.length == newfriends.length){ 
      deferred.resolve(newfriendsinfo); 
     } 
    } 

})(newfriendid, newfriendagreed); 
+0

非常感謝!這樣做,我認爲我現在對它的完成有了更好的理解:)我很感謝幫助! – Robin

+1

歡迎。我認爲你需要改變問題的標題。 「用承諾循環獲取firebase對象」。也許這不是最好的標題,但你現在擁有的是完全錯誤的。 –

+0

是的你是對的,只是做:) – Robin