如何使JavaScript承诺等待在()循环内部解决另一个承诺

时间:2017-10-02 03:13:52

标签: javascript angularjs firebase promise angular-promise

我有一个AngularJS应用程序,我使用promises从firebase数据库中获取数据。

这是我的home-controller

$scope.wallets;

walletDAO.getWalletsByUserId(auth.uid)
.then(function(wallets){
    $scope.wallets = wallets;
    $scope.$apply();
})
.catch(function(error){
    console.log(error);
});

这是我调用walletDAO的服务中的两种方法:

this.getWalletsByUserId = function(id) {
    return new Promise(function(resolve, reject) {
        //codigo aqui
        var dbRef = database.ref("users/" + auth.currentUser.uid);
        dbRef.on('value', function(data) {
            //console.log("Wallet IDs Retrieved!");
            var userOnDB = data.val();
            var walletIds = userOnDB.wallets;
            var wallets = [];
            for (i = 0; i < walletIds.length; i++) {
                var x = getWalletById(walletIds[i])
                .then(function(wallet){
                    wallets.push(wallet);
                })
                .catch(function(error){
                    console.log(error);
                });
            }
            resolve(wallets);
        }, function(error) {
            reject(error);
        });
    });
};

var getWalletById = function(id) {
    return new Promise(function(resolve, reject) {
        var dbRef = database.ref("wallets/" + id);
        dbRef.on('value', function(data) {
            //console.log("Wallet Retrieved!");
            var wallet = data.val();
            //console.log(wallet);
            resolve(wallet);
        }, function(error) {
            reject(error);
        });
    });
};

第二种方法getWalletById接收钱包ID并从firebase数据库返回wallet个对象。这个方法是在getWalletsByUserId循环内的第一个方法for上调用的,它应该等待第二个方法在迭代到下一个之前返回钱包,这样它就可以将它推入数组中。问题是它不等待,并且代码在解析.then()之前在home-controller上执行getWalletById方法,使$scope.wallets为空。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

使用$q.all()等待所有子承诺完成

$q.all(walletIds.map(function(id){
  return getWalletById(id);
})).then(function(wallets){
  ...
})

答案 1 :(得分:1)

不是使用ref.on方法制作ES6承诺,而是使用ref.once方法并将其带入$q.when的AngularJS执行上下文中:

function getWalletById(id) {
    var dbRef = database.ref("wallets/" + id);
    var es6Promise = dbRef.once('value');
    return $q.when(es6Promise);
}

只有在AngularJS执行上下文中应用的操作才会受益于AngularJS数据绑定,异常处理,属性监视等。

在父函数中使用$q.allpromise chaining

this.getWalletsByUserId = function(id) {
    var dbRef = database.ref("users/" + auth.currentUser.uid);
    var es6Promise = dbRef.once('value')
      .then(function(snapshot)
        //console.log("Wallet IDs Retrieved!");
        var userOnDB = snapshot.val();
        var walletIds = userOnDB.wallets;
        var promiseList = walletIds.map(function(id){
            return getWalletById(id);
        });
        return $q.all(promiseList);
    });
    return $q.when(es6Promise);
};

.then方法返回新的承诺,通过successCallbackerrorCallback的返回值解析或拒绝(除非该值是承诺) ,在这种情况下,使用promise chaining)解析该承诺中解决的值。