延迟的 Rxjs BehaviorSubject 机制

deferred Rxjs BehaviorSubject mechanism

我有以下需求。

我有一个带有 BehaviorSubject 的 Angular 服务。 一个 http 请求已完成,完成后 BehaviorSubject.next 方法将用该值调用。 此值可以在单个页面的生命周期内更改。

不同的订阅者注册到它并在它发生变化时被调用。

问题是当 http 请求挂起时,BehaviorSubject 已经包含默认值并且订阅者已经立即获得该值。

我想要的是订阅者必须等到 http 请求完成(延迟)并在 http 请求完成并设置值时获取值。 所以我需要的是某种延迟行为主体机制。

我如何使用 rxjs 实现它?

另一个要求是,如果我在一个方法中订阅了 behaviorsubject,我们希望订阅者获得第一个非默认值并且订阅结束。我们不希望重新执行函数中的本地订阅。

对您的行为主题使用过滤器,这样您的订阅者就不会获得第一个默认发出的值:

mySubject$: BehaviorSubject<any> = new BehaviorSubject<any>(null);

httpResponse$: Observable<any> = this.mySubject$.pipe(
  filter(response => response)
  map(response => {
     const modifyResponse = response;
    // modify response
    return modifyResponse;
  }),
  take(1)
);
this.httpResponse$.subscribe(response => console.log(response));

this.myHttpCall().subscribe(response => this.mySubject$.next(response));

如果需要,您当然可以将可观察到的 httpResponse$ 包装在一个方法中。

我认为您想推迟发出的默认值这一事实会立即引起您为什么要使用 BehaviorSubject 的疑问。让我们记住:使用 BehaviorSubject(而不是 Subject 或普通 Observable)的主要原因是 立即 向任何订阅者发出一个值。

如果你需要一个 Observable 类型,你需要控制生产者(通过 .next([value]))and/or 你想要开箱即用的多播订阅,那么 Subject 合适。

如果除此之外还有一个额外的要求是订阅者立即需要一个值,那么你需要考虑BehaviorSubject.

如果您没有说您需要更新来自其他 non-http events/sources 的值,那么我会建议使用 shareReplay(1) 模式。尽管如此...

private cookieData$: Subject<RelevantDataType> = new 
Subject<RelevantDataType>(null);


// Function for triggering http request to update
// internal Subject.
// Consumers of the Subject can potentially invoke this 
// themselves if they receive 'null' or no value on subscribe to subject
public loadCookieData(): Observable<RelevantDataType> {
    this.http.get('http://someurl.com/api/endpoint')
        .map(mapDataToRelevantDataType());
}

// Function for dealing with updating the service's 
// internal cookieData$ Subject from external 
// consumer which need to update this value
// via non-http events
public setCookieData(data: any): void {
    const newCookieValue = this.mapToRelevantDataType(data); // <-- If necessary
    this.cookieData$.next(newCookieValue); // <-- updates val for all subscribers
}

get cookieData(): Observable<RelevantDataType> {
    return this.cookieData$.asObservable();
}

解决方案基于OP评论等。 - 处理订阅主题类型。 - 处理无法直接 'next' 新值的外部订阅者 - 处理能够在 Subject 类型上设置新值的外部生产者 - 处理在 http 请求未决时不提供默认值的问题