从嵌套的forEach循环中获得承诺?

时间:2017-02-05 16:02:31

标签: typescript firebase promise firebase-realtime-database angularfire2

我试图遍历Firebase列表(使用AngularFire2),我希望得到一个Promise来指示嵌套循环何时完成,以便我可以处理第二个操作。我使用以下代码:

  console.log('START');
  this.af.database.list('Sites/123123/Users')
    .map(users => {
      users.map(user => {
        console.log('found a user ', user);
        this.af.database.list('registeredUsers/' + user.$key + '/Sites')
          .forEach(sites => {
            sites.forEach(site => {

              if (site.$value == '123123') {
                console.log('found site ', site.$key);
              }
            });
          });
      });
    }).first().toPromise().then(function (x) {
      console.log('ALL DONE')
    });

输出结果为:

console output

但是我只在外部循环之后获得Promise,而不是等待嵌套循环完成。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

你在地图调用中缺少return语句,因为你在用户可观察的第一个地图中生成了新的Observable,你应该在这里使用mergeMap:

console.log('START');
this.af.database
    .list('Sites/123123/Users')
    .mergeMap(users => {
        return users.map(user => {
            console.log('found a user ', user);
            return this.af.database.list('registeredUsers/' + user.$key + '/Sites')
                .forEach(sites => {
                    sites.forEach(site => {
                        if (site.$value == '123123') {
                            console.log('found site ', site.$key);
                        }
                    });
                });
        });
    })
    .first().toPromise().then(x => {
        console.log('ALL DONE')
    });

这里我有一个简化的代码版本,消除了对firebase应用程序的依赖:



//const Rx =  require('rxjs'); // require Rx on nodejs instead of html script tag
const usersObservable = Rx.Observable.from([[{ id: 1, $key: 123 }]]);

const sitesObservable = Rx.Observable.from(
    new Promise((resolve) => {
        setTimeout(() => {
            resolve([{ $value: '123123', $key: 'site1' }, { $value: '0', $key: 'site2' }])
        }, 500);
    })
);

console.log('START');
usersObservable
    .mergeMap((users) => {
        return users.map(user => {
            console.log('found a user ', user);
            return sitesObservable
                .forEach(sites => {
                    sites.forEach(site => {
                        if (site.$value == '123123') {
                            console.log('found site ', site.$key);
                        }
                    });
                });
        });
    })
    .first().toPromise().then(x => {
        console.log('ALL DONE')
    });

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.js"></script>
&#13;
&#13;
&#13;

以下是生成的输出:

START
found a user  {
  "id": 1,
  "$key": 123
}
found site  site1
ALL DONE

添加了特定的firebase代码后,您的代码应如下所示:

console.log('START');
var siteUsers = this.af.database.list('Sites/-KcF5J9SoSHDrUEYO-Ed/Users');

siteUsers
    .mergeMap(users => {
        console.log('users = ', users);
        return users.map(user => {
            console.log('found a user ', user);
            return this.af.database.list('registeredUsers/' + user.$key + '/Sites')
                .forEach(sites => {
                    console.log('sites = ', sites)
                    sites.forEach(site => {
                        if (site.$value == '-KcF5J9SoSHDrUEYO-Ed') {
                            console.log('found site ', site.$key);
                        }
                    });
                });
        });
    })
    .first().toPromise().then(x => {
        console.log('ALL DONE')
    });

答案 1 :(得分:1)

@Kalle

我也尝试过这种方式,同样如此:

 console.log('START');
  var siteUsers = this.af.database.list('Sites/-KcF5J9SoSHDrUEYO-Ed/Users');
  const siteUsersObservable = Observable.from(siteUsers);

  siteUsersObservable
    .map(users => {
      console.log('users = ', users);
      return users.map(user => {
        console.log('found a user ', user);
        var userSites = this.af.database.list('registeredUsers/' + user.$key + '/Sites');
        const userSitesObservable = Observable.from(userSites);
        return userSitesObservable
          .forEach(sites => {
            console.log('sites = ', sites)
            sites.forEach(site => {
              if (site.$value == '-KcF5J9SoSHDrUEYO-Ed') {
                console.log('found site ', site.$key);
              }
            });
          });
      });
    })
    .first().toPromise().then(x => {
      console.log('ALL DONE')
    });

并且firebase结构是这样的:

我的结果是: