使用 promises 循环获取 firebase 对象

Fetching firebase objects in loop with promises

如果可能的话,我需要一些关于承诺的帮助。我是 AngularJS 的新手,不知道如何处理我遇到的问题。基本上,问题是我有两个异步初始化的不同数组,同时最终将两个数据存储在同一个数组中,并在多个项目的 for 循环中执行此操作。我遇到的错误是,虽然它加载了正确数量的项目,但它显示了所有不同的用户数据,但没有显示不同的图片。每个条目显示的图片相同。在整个代码部分的末尾,您会发现:

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;

}

问题肯定出在这段代码中。

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 你仍然会有问题。 您在 promise 中使用变量 newfriendidnewfriendagreed,这是在 promise in cycle 之外创建的。这里有 Closures.

的问题

调用 asyncUpdateFriendsInfo 函数时会发生什么。

当 for 循环完成时,将发送所有请求(但尚未收到响应)并且 newfriendidnewfriendagreed 指向 newfriends 的最后一条记录的 $idagreed。所以在 newfriendsinfo 中,所有 newfriendid 都是一样的,并且最后 newfriendid.

查看“Asynchronous Process inside a javascript for loop”这个问题“=32=]

如果确实如此,您应该替换此代码

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);