Firebase如何取消订阅

时间:2017-07-03 07:40:48

标签: javascript firebase ionic-framework firebase-authentication angularfire2

我正在使用Ionic2Angularfire2访问Firebase Authentication

我访问以下rxjs/Observable

chats.ts

  this.firelist = this.dataService.findChats();
  this.subscription = this.firelist.subscribe(chatItems => {
     ...
  });

  ngDestroy() {
    this.subscription.unsubscribe();
  }

dataService.ts

findChats(): Observable<any[]> {
        this.firebaseDataService.findChats().forEach(firebaseItems => {
           ...
           observer.next(mergedItems);
        });
}

firebaseDataService.ts

findChats(): Observable<any[]> { // populates the firelist
    return this.af.database.list('/chat/', {
        query: {
            orderByChild: 'negativtimestamp'
        }
    }).map(items => {
        const filtered = items.filter(
            item => (item.memberId1 === this.me.uid || item.memberId2 === this.me.uid)
        );
        return filtered;
    });
}

此外,在Firebase身份验证中,我有以下实时数据库规则:

  "rules": {
      ".read": "auth != null",
      ".write": "auth != null",
  }

问题

这在用户登录时完美无缺(即auth != null),但是一旦用户退出,auth == null,我就会收到以下错误:

  

错误错误:未捕获(在承诺中):错误:在/ chat处的permission_denied:   客户无权访问所需数据。错误:   permission_denied at / chat:客户没有访问权限   想要的数据。

问题

正如您在上面的代码中看到的那样,我尝试从Firebase身份验证服务unsubscribe,但必须正确执行此操作。如果有人可以建议我应该unsubscribe如何停止我的应用程序查询Firebase数据库,我将非常感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

这不是问题的确切答案,但我的论点是,如果我们以其他方式这样做,我们将永远不会遇到这个问题。

P.S:我从未使用过firebase,我使用AWS所以firebase代码可能不准确,我们讨论它。

这是我的版本:

findChats(): Observable<any[]> { // populates the firelist
    return 
      this.authService.getCurrentUser()
        .flatMap(user => user === null ? 
          Observable.empty():        
          this.af.database.list('/chat/', {
             query: {
                orderByChild: 'negativtimestamp'
             }
           })
          .map(items => 
             return items.filter(
               item => (
                  item.memberId1 === this.me.uid || 
                  item.memberId2 === this.me.uid
               )
             ) 
          )
     );
}

验证服务

public currentUser = new BehaviorSubject(null);

constructor(){

    firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
           // User is signed in.
           currentUser.next(user);
        } else {
         // No user is signed in.
           currentUser.next(null);
        }
    });

}    

代码非常原始,但我希望它传达了这个想法。在这里,我观察用户身份验证状态并执行flatMap来获取数据。如果用户注销,则auth状态将更改为null,因此UI数据将更改为空列表。即使用户没有注销,他仍然无法看到数据。

更新

重构其他答案:

findChats(){
   return Observable.merge(
       this.firebaseDataService
           .findChats()
           .flatMap(chats => Observable.from(chats)),
       this.localDataService
           .findChats()
           .flatMap(chats => Observable.from(chats))
   )
   .filter(chat => !!chat)
   .toArray()
   .map(chats => [
      ...chats.sort(
        (a, b) => 
           parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp))
      ]
   );  
}

除非您使用Subject缓存响应,否则请勿在服务中使用subscribe

答案 1 :(得分:0)

unsubscribe正常运作。问题是我使用的以下函数导致它因某种原因订阅了两次:

findChats(): Observable<any[]> {
    return Observable.create((observer) => {
        this.chatSubscription2 = this.firebaseDataService.findChats().subscribe(firebaseItems => {
            this.localDataService.findChats().then((localItems: any[]) => {
                let mergedItems: any[] = [];
                if (localItems && localItems != null && firebaseItems && firebaseItems != null) {
                    for (let i: number = 0; i < localItems.length; i++) {
                        if (localItems[i] === null) {
                            localItems.splice(i, 1);
                        }
                    }
                    mergedItems = this.arrayUnique(firebaseItems.concat(localItems), true);
                } else if (firebaseItems && firebaseItems != null) {
                    mergedItems = firebaseItems;
                } else if (localItems && localItems != null) {
                    mergedItems = localItems;
                }
                mergedItems.sort((a, b) => {
                    return parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp);
                });
                observer.next(mergedItems);
                this.checkChats(firebaseItems, localItems);
            });
        });
    });
}

由于某种原因,上面的第3行被调用两次(即使该函数只被调用一次)。这是创建第二个subscription,第一个subscription永远不会unsubscribed

因此,Observable的创建似乎不正确。我不确定是什么;是创建Observable的正确方法。