如何在snapshot.foreach中访问变量范围之外的值

时间:2018-09-11 10:51:06

标签: javascript angular firebase firebase-realtime-database

return statement在变量的foreach之外返回null值,我知道foreach循环会创建自己的范围,我需要返回该值,我该怎么做.....

this.selectedUserMessages = this.changeUserList.switchMap(Userid => {
   if (Userid) {

    var self = this;
    this.loadingSerivice.isLoading.next(true);
    var ref = db.database.ref(`wfffsdf/usesdfdsfsrs/${Userid}/ress`);
    var i = 0;
    ref.once("value")
     .then(function(snapshot) {

      snapshot.forEach(function(childSnapshot) {
       var key = childSnapshot.key;
       // childData will be the actual contents of the child
       var invitedList = childSnapshot.val();
       self.invList.push({
        invitedid: invitedList
       });
       var invitedlistid = self.invList[i]['invitedid']['invitedBy'];
       //console.log(invitedlistid);
       if (invitedlistid == "asfsafafasfsafsafs") {
        //console.log("thread"+threadKey);
        self.ChatKey = key;
        //console.log(self.ChatKey+""+ db.database.ref(`1dfgsdfgdfhfdh/tdfsdfhsfhfhfdh/${key}/messages`)); 
       }
       i++;
      });
      self.chatMessages = self.getMessages(self.ChatKey);
      //  console.log(self.chatMessages);
     });
    return this.chatMessages;
   }
   return of(null);
  }

返回this.chatMessages为空值...

1 个答案:

答案 0 :(得分:1)

最简单的答案是变量的范围不是问题。在Javascript中,var的作用域是周围的函数。在提供的示例代码中,forEach被传递给function,因此其所有变量的作用域均与声明的作用域相同。外部变量被捕获在内部函数中,因此它们也可以正常运行。

问题在于内部promiseswitchmap返回值之前没有解析。


要完全了解正在发生的事情,让我们看一下代码当前正在执行的操作以及应该执行的操作。

为了争辩,我将假设以下定义(即使我知道它们是不正确的):

selectedUserMessages : Observable<[]>;
      changeUserList : Observable<String>;

此处,changeUserList是代表当前所选UserId的字符串事件流。 selectedUserMessages将是与当前所选用户相关联的消息数组。

上面的代码简化为以下含义:

this.selectedUserMessages =
  // when changeUserList changes, switch selectedUserMessages to this new stream
  this.changeUserList.switchMap(Userid => {
    if (Userid) {

      // grab DB reference to user child list
      var ref = db.database.ref(`wfffsdf/usesdfdsfsrs/${Userid}/ress`);

      // CREATE A PROMISE TO QUERY THE DATABASE
      ref.once("value") // query once
        .then(function (snapshot) {
          snapshot.forEach(function (childSnapshot) {
            var key = childSnapshot.key;
            var val = childSnapshot.val();

            // process child
          });

          // store result
          this.chatMessages = this.getMessages(this.ChatKey);

        }); // END OF PROMISE

      // RETURN IMMEDIATELY, BEFORE PROMISE RESOLVES
      return this.chatMessages;
    }
    return of(null); // return null stream
  }

问题是switchmap调用在内部承诺解决之前返回this.chatMessages


switchmap具有一个有趣的功能:您可以可以从switchmap内部返回一个承诺,它将等待该承诺。这是mix Promises and Observables的一种方式。

从switchmap内部返回一个承诺,就像:

this.selectedUserMessages =
  // when changeUserList changes, switch selectedUserMessages to this new stream
  this.changeUserList.switchMap(Userid => {
    if (Userid) {

      // grab DB reference to user child list
      let ref = db.database.ref(`wfffsdf/usesdfdsfsrs/${Userid}/ress`);

      // !!!! RETURN A PROMISE TO QUERY THE DATABASE !!!!
      return ref.once("value") // query once
        .then(function (snapshot) {

          let results = [];
          snapshot.forEach(function (childSnapshot) {
            let key = childSnapshot.key;
            let val = childSnapshot.val();
            // process child //
            results.push(/*processing results*/);
          });

          return results;

        }); // END OF PROMISE
    }
    else
      return of(null); // return null stream
  }

话虽这么说,但还有一种替代方案,可以混合用于Firebase的Promises和Observables RxFire。这是Firebase团队使用RxJS Observables的相对较新的软件包。由于您正在使用实时数据库,因此您将需要look at these examples。 List()将发出子更改流。您可以通过pipe()运算符map()将此流进行其他处理(或如示例中那样提取val()并包含密钥)。您在map()中执行的操作类似于在forEach中执行的操作。

AngularFirebase有一个在FireStore上使用RxFire的示例。