【问题标题】:how to access the value of variable outside its scope in snapshot.foreach如何在 snapshot.foreach 中访问其范围之外的变量的值
【发布时间】:2018-09-11 23:53:17
【问题描述】:

return 语句在变量的 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);
  }

return this.chatMessages 给出空值...

【问题讨论】:

  • 在 Javascript 中,var 具有函数级范围。 ForEach 创建它自己的范围,因为您正在向它传递一个函数。但是,这是内部变量的范围。外部变量被捕获并在 ForEach 内部正常工作。范围不是你的问题。您的问题是您正在使用 Promise 来处理数据库查询,然后尝试立即返回流。您正在混合 Observables 和 Promise。 then 中的所有内容都在 return this.chatMessages 之后执行。给我一分钟给你找一个使用 Rx 的例子。
  • 感谢您的回复@JamesPoag,我是 Angular 和 Firebase 的新手
  • 好的,这是RxFire。这是来自 Firebase 团队的一个相对较新的包,用于使用 RxJS Observables。由于您使用的是实时数据库,因此您需要look at these examples。 List() 将发出子更改流。您可以通过map() 运算符pipe() 此流进行额外处理(或提取val() 并包含key,如示例中所示)。您在 map() 中所做的与您在 ForEach 中所做的类似。
  • Here is a video 演示使用 RxFire。他们使用 FireStore 而不是 Realtime 数据库,但该网站上还有其他与 Rx observables 相关的视频。
  • 谢谢,会调查的

标签: javascript angular firebase firebase-realtime-database


【解决方案1】:

简短的回答是变量的范围不是问题。在 Javascript 中,var 的作用域是周围的函数。在提供的示例代码中,forEach 被传递了一个 function,因此它的所有变量都按照声明的范围限定。外部变量在内部函数中被捕获,因此它们的行为也正常。

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


要全面了解发生了什么,让我们看一下代码当前正在做什么以及它应该做什么。

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

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

这里,changeUserList 是一个字符串事件流,代表当前选定的UserIdselectedUserMessages 将是与当前选定用户关联的消息数组。

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

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 内部返回一个 Promise 如下所示:

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() 将发出子更改流。您可以通过map() 运算符pipe() 此流进行额外处理(或提取 val() 并包含示例中的密钥)。您在 map() 中所做的与您在 forEach 中所做的类似。

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

【讨论】:

  • 感谢您的回复@james,您能告诉我rxFire 将如何与实时数据库一起工作,以及上述答案返回结果吗?在 foreach 之外未定义
  • 另外,如果我在 promise 中写入返回结果,它不会订阅更改,
  • this.chatroom.selectedUserMessages.subscribe(userChatMessages =>{ if(userChatMessages){ // console.log("Hello"); this.userChatMessages = userChatMessages; // console.log("saasasf "+userChatMessages); this.loadingService.isLoading.next(false); } }) );
  • 您能否在foreEach 处设置一个调试中断并逐步检查以确保正确生成results
  • 另外,切换到箭头函数...snapshot.forEach(function (childSnapshot) { 应该是snapshot.forEach(childSnapshot =&gt; {
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-11
  • 1970-01-01
  • 2020-08-06
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
相关资源
最近更新 更多