RxJS Observable 和 Observer 问题

RxJS Observable & Observer issues

我有一个 Angular 2 服务,它执行几个步骤来验证和登录应用程序用户。每当我尝试在我的 Observer 上调用 next() 时,我都会收到一个未定义的错误。当实例化 Observable 时,我唯一可以成功调用 next() 的地方是在构造函数内部。

如果我调用 authenticateUser(),我会收到一个错误,指出 this.isLoggedIn 未定义。

AuthService.ts

public isLoggedIn$: Observable<boolean>;
private isLoggedIn: Observer<boolean>;

constructor(...) {

    this.isLoggedIn$ = new Observable<boolean>(
        (observer: Observer<boolean>) => {
            this.isLoggedIn = observer;

            // this works fine
            this.doLogin();

        }).share()

}

private doLogin = ():void => {

    let context:AuthContextModel = this.authContextService.getAuthContext();

    if (context) {

        let isAuthenticated = this.isAuthenticated(context);

        if (isAuthenticated) {

            this.doCreateCurrentUserContext(context)
                .then((result) => {return this.doNotifyLoggedInStatus(result);});
        }
    }
};


private doNotifyLoggedInStatus = (result:boolean):Promise<boolean> => {

    this.isLoggedIn.next(result);

    return new Promise((resolve, reject) => {
        return resolve(true);
    });
};


public authenticateUser = (user: string, pass: string):Promise<boolean> => {
    return this.doFetchToken(user, pass)
        .then((fetchTokenData) => {return this.doStoreToken(fetchTokenData);})
        .then((authContext) => {return this.doCreateCurrentUserContext(authContext);})
        .then((result) => {return this.doNotifyLoggedInStatus(result);});

};

如果您想在 Observable 实例化之外的 Observer 上调用 .next(),您应该使用 Subject 而不是单独的 Observables 和 Observers。主体充当两者。您可以从将事件传递给它的地方单独订阅它们。

Subject 有多种类型,但对于您的情况,我建议使用 BehaviorSubject。每当您订阅它时,它不仅会捕获未来的事件,还会 return 在订阅发生之前触发的 last 事件。这对于身份验证组件很有用,因为您不必编写单独的代码来成功登录并实际检查用户是否已通过身份验证(或稍后注销)。这也很简单。

import { BehaviorSubject } from 'rxjs/Rx'; 

//...
  public isLoggedIn: BehaviorSubject<boolean> = BehaviorSubject.create();

  constructor(...) { }

  private doLogin():void {

    //... Do the log in
    this.isLoggedIn.next(true);

  };

无论你想检查登录状态,你需要做的就是获取 BehaviorSubject 并订阅它。订阅发生在调用 doLogin() 之前还是之后并不重要。

如果您打算在刷新时保留登录状态,您需要在构造函数中做的就是检查身份验证并像往常一样在 BehaviorSubject 上调用 .next(true)

另请参阅:

ReactiveX Subject docs

Intro to Rx BehaviorSubjects