【问题标题】:Fetching firebase objects in loop with promises使用 Promise 循环获取 firebase 对象
【发布时间】:2016-10-21 16:34:12
【问题描述】:

如果可能的话,我需要一些关于承诺的帮助。我是 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;

}

【问题讨论】:

标签: javascript angularjs firebase firebase-realtime-database angularfire


【解决方案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,您仍然会遇到问题。 您在 promise 中使用变量 newfriendidnewfriendagreed,这是在循环中的 promise 之外创建的。这里有Closures的问题。

这是调用asyncUpdateFriendsInfo 函数时会发生的情况。

当 for 循环完成时,所有请求都将被发送(但尚未收到响应)并且 newfriendidnewfriendagreed 指向 newfriends 的最后一条记录的 $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);

【讨论】:

  • 非常感谢!做到了,我想我现在对它是如何完成的有了更好的理解:)感谢您的帮助!
  • 欢迎。我认为您需要将问题的标题更改为类似的内容。 “使用 promise 循环获取 firebase 对象”。也许这不是最好的标题,但你现在拥有的是完全错误的。
猜你喜欢
  • 2018-01-21
  • 1970-01-01
  • 2019-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多