【问题标题】:Subscribing to an observable before it's been populated在填充之前订阅 observable
【发布时间】:2018-03-13 18:10:44
【问题描述】:

我正在尝试为 Angular 4 项目创建用户配置文件服务,并且在如何正确初始化和更新可观察的配置文件对象方面遇到了一些困难。目前,当用户进行身份验证(通过 Firebase)时,AuthService 通过后者的 initialize() 函数将用户的身份验证信息传递给 UserProfileService。 UserProfileService 然后查找用户的个人资料(如果尚不存在,则创建一个)并使用该个人资料填充一个公共可观察对象。

我遇到的问题是应用程序的其他部分试图在这一切发生之前订阅可观察的配置文件。我最初是通过 ...

初始化 observable
public profileObservable: UserProfile = null;

...这当然会导致“subscribe() 在 null 上不存在”错误,所以我将其更改为 ...

public profileObservable: Observable<UserProfile> = Observable.of();

这至少不会引发任何错误,但在我将 Firebase 对象映射到它之前订阅 profileObservable 的任何内容都不会更新。

下面的 user-profile.service.ts 的完整代码。我仍然在努力弄清楚其中一些是如何工作的,所以希望有人能阐明一些看法。谢谢!

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { FirebaseListObservable, FirebaseObjectObservable, AngularFireDatabase } from 'angularfire2/database';
import * as firebase from 'firebase/app';

export class UserProfile {
    $exists: Function;
    display_name: string;
    created_at: Date;
}

@Injectable()
export class UserProfileService {
    private basePath: string = '/user-profiles';
    private profileRef: FirebaseObjectObservable<UserProfile>;
    public profileObservable: Observable<UserProfile> = Observable.of();

    constructor(private db: AngularFireDatabase) {
        // This subscription will never return anything
        this.profileObservable.subscribe(x => console.log(x));
    }

    initialize(auth) {
        this.profileRef = this.db.object(`${this.basePath}/${auth.uid}`);
        const subscription = this.profileRef.subscribe(profile => {
            if (!profile.$exists()) {
                this.profileRef.update({
                    display_name: auth.displayName || auth.email,
                    created_at: new Date().toString(),
                });
            } else subscription.unsubscribe();
        });

        this.profileObservable = this.profileRef.map(profile => profile);

        // This subscription will return the profile once it's retrieved (and any updates)
        this.profileObservable.subscribe(profile => console.log(profile));
    }
};

【问题讨论】:

    标签: javascript angular rxjs angularfire2


    【解决方案1】:

    一旦构建了可观察引用,就不得更改它们。我发现将订阅者与数据源正确分离的方法是使用中间Subject,它既是观察者又是可观察者。

    您的代码将如下所示:

    import { Observable } from 'rxjs/Observable';
    import { Subject } from 'rxjs/Subject';
    
    ...
    
    export class UserProfileService {
        ...
        public profileObservable = new Subject<UserProfile>(); 
    
        constructor(private db: AngularFireDatabase) {
            // This subscription now works
            this.profileObservable.subscribe(x => console.log(x));
        }
    
        initialize(auth) {
            const profileRef = this.db.object(`${this.basePath}/${auth.uid}`);
    
            ...
    
            profileRef.subscribe(this.profileObservable);
        }
    };
    

    【讨论】:

    • 您可能会使用new ReplaySubject&lt;UserProfile&gt;(1) 获得更好的运气,以便迟到的订阅者仍然能够收到提供的最新用户配置文件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    相关资源
    最近更新 更多