RxJS寻找类似“ delayUntil”的东西

时间:2019-03-02 22:14:13

标签: angular typescript rxjs reactive-programming

我有两个函数,一个返回observableA,另一个返回observableB。我希望getter和observableB的订阅都延迟到observableA完成为止(但是当我订阅observableB,{{1}时也可能是这种情况}已经完成)。

我已经尝试使用observableApipe,但是很遗憾,这只会阻止执行,并且如果skipUntil尚未完成,也不会延迟执行。

observableA

找到一种非常类似于RxJS的方式会很棒:)


更新1:functionA() { this.observableA$ = getObservableA() this.observableA$.subscribe(_ => { // A: This line should execute *before* line B }) } functionB() { this.observableB$ = getObservableB() // This getter should execute *after* line A this.observableB$.subscribe(_ => { // B: This line should execute *after* line A }) } // Two functions are called independently functionA() functionB() 的问题: 如前所述,两个函数都被独立调用,当像建议的那样使用concat时,将导致observableA$的双重执行。此外,concat中的订阅将被执行两次,我不希望执行。

functionB

更新2:@Wilhelm Olejnik通过使用其他functionA() { this.observableA$ = getObservableA() this.observableA$.subscribe(_ => { // A: This line should execute *before* line B }) } functionB() { Observable.concat( this.observableA$, // I get executed once again :( Observable.defer(() => getObservableB()) // To prevent earlier execution ).subscribe(() => { // B: This line should execute *after* line A console.log("I'm logged twice, once for each observable :(") }) } // Two functions are called independently functionA() functionB()

解决了该问题

2 个答案:

答案 0 :(得分:1)

我遇到了类似的情况,我创建了一个服务SyncService以同步可观察对象。对我来说,ObsAObsB来自不同的组件。 ComponentA加载了自己的数据后,得到了ComponentB所需的一些初始化数据。

ComponentA中,我订阅了ObsA(从getInitData()返回)并调用了同步服务:

public initialize() {
   this.apiSvc.getInitData().subscribe((initData) => {
      this.data = initData;
      this.syncService.setA(initData);
   }
}

然后,在ComponentB中,我订阅ObsB(从getBData()返回),然后订阅同步服务:

public loadBData() {
    this.apiSvc.getBData().subscribe((dataB) => {
        this.syncService.setB(dataB).subscribe((dataA, dataB) => {
            this.doStuffWithAAndB(dataA, dataB);
        }
    }
}

最后,同步服务如下所示:

@Injectable
export class SyncService {
    private dataA: DataA = null;
    private dataB: DataB = null;
    private gotAEvent: new EventEmitter<DataA>();

    public setA(dataA: DataA) {
        this.dataA = dataA;
        if (this.dataB != null) {
            // ObsB was already resolved!
            this.gotAEvent.emit(dataA);
        }
    }

    public setB(dataB: DataB) {
        this.dataB = dataB;
        if (this.dataA != null) {
            return of({this.dataA, this.dataB});
        } else {
            return this.gotAEvent().map((dataA: DataA) => {
                return {dataA, dataB};
            }
        }
    }
}

答案 1 :(得分:1)

如果我正确理解了所有内容,则希望延迟执行getObservableB,直到将一些可观察到的属性分配给属性observableA$

也许可以通过一些Proxy技巧来实现,但是我认为将observableA$更改为空初始化的BehaviorSubject会更容易。然后您可以观察observableA$并在发出非空信号时创建observableB$

https://stackblitz.com/edit/rxjs-mm2edy

import { of, BehaviorSubject, timer } from 'rxjs';
import { filter, switchMap, mapTo, tap } from 'rxjs/operators';

const getObservableA = () => timer(100).pipe(
  tap(() => console.log('getObservableA')),
  mapTo('A')
);

const getObservableB = () => timer(100).pipe(
  tap(() => console.log('getObservableB')),
  mapTo('B')
);

class Test {
  // init observableA$ as BehaviorSubject with null state
  observableA$ = new BehaviorSubject(null);
  observableB$;


  functionA() {
    getObservableA().subscribe(val => {
      console.log(val)
      this.observableA$.next(val);      // notify subscribers that observableA$ is ready
    });
  }

  functionB() {
    this.observableB$ = this.observableA$.pipe(
      filter(value => value !== null),            // ignore observableA$ until initalized
      switchMap(value => getObservableB())
    )
    this.observableB$.subscribe(console.log)
  }
}

const test = new Test();

test.functionB();
setTimeout(() => test.functionA(), 500);

// getObservableA
// A
// getObservableB
// B