使用promises在循环中获取firebase对象

时间:2016-10-20 15:18:37

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

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

}

1 个答案:

答案 0 :(得分: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函数时会发生的情况。

当周期结束时,将发送所有请求(但尚未收到回复),newfriendidnewfriendagreed指向newfriends的最后一条记录&#39; s $idagreed。因此,在newfriendsinfo newfriendid中,所有newfriendid都是相同的,并且将是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); } }); });

查看&#34; Asynchronous Process inside a javascript for loop&#34;

的这个问题

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

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

这样的事情

{
  "name": "First",
  "version": "0.0.0",
  "devDependencies": {
    "aspnet-webpack": "^1.0.6",
    "bootstrap": "^3.3.6",
    "css-loader": "^0.23.1",
    "expose-loader": "^0.7.1",
    "extendify": "^1.0.0",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.5",
    "jquery": "^2.2.1",
    "raw-loader": "^0.5.1",
    "style-loader": "^0.13.0",
    "ts-loader": "^0.8.1",
    "typescript": "^1.8.2",
    "url-loader": "^0.5.7",
    "webpack": "^1.12.14",
    "webpack-hot-middleware": "^2.10.0"
  },
  "dependencies": {
    "@angular/common": "2.0.0-rc.4",
    "@angular/compiler": "2.0.0-rc.4",
    "@angular/core": "2.0.0-rc.4",
    "@angular/http": "2.0.0-rc.4",
    "@angular/platform-browser": "2.0.0-rc.4",
    "@angular/platform-browser-dynamic": "2.0.0-rc.4",
    "@angular/platform-server": "2.0.0-rc.4",
    "@angular/router": "3.0.0-beta.2",
    "angular2-universal": "^0.104.5",
    "aspnet-prerendering": "^1.0.2",
    "css": "^2.2.1",
    "es6-shim": "^0.35.1",
    "isomorphic-fetch": "^2.2.1",
    "materialize-css": "^0.97.7",
    "preboot": "^2.0.10",
    "rxjs": "5.0.0-beta.6",
    "webpack-externals-plugin": "^1.0.0",
    "zone.js": "^0.6.12"
  }
}