繁体   English   中英

如何以非阻塞方式组合可观察对象?

[英]How to combine observables in a non-blocking way?

我有一个Observable集合,每个Observable都检索不同的数据类型。 我正在链接那些Observable来获取我想要的所有数据。 事实是所有这些信息都是独立的,因此加载一个信息不应该阻止或干扰加载其他信息。 这是我无法实现的。

这是我目前所做的一个例子:

  getAll(): Observable<any[]> {
    return this.getHome().pipe(
      tap((home: Home) => this.application = home),
      mergeMap((home: Home) =>
        combineLatest([
          this.getAssets(home.images).pipe(defaultIfEmpty([])),
          this.getStyling(home.styling).pipe(defaultIfEmpty({})),
          this.getCategories(home.categories).pipe(defaultIfEmpty([])),
        ])
      )
    );
  }

在这里,Observable被成功链接,所以我得到了我想要的所有数据,但是一旦前一个完成, combineLatest()会执行下一个请求,并且一旦完成所有内容,父节点就会发出收集的数据,从而产生延迟。 我一直在尝试使用merge()而不是combineLatest()以便收到的每个数据立即发送到父Observable,但显然我不能这样做

那么,我如何设法链接那些Observable,以便子Observable中的每个提交直接发送到父Observable?

你需要forkJoin ,它返回一个Array ,其中包含每个Observable的结果(与forkJoin参数的顺序相同)。

  getAll(): Observable<any[]> {
    return this.getHome().pipe(
      tap((home: Home) => this.application = home),
      mergeMap((home: Home) =>
        forkJoin(
          this.getAssets(home.images).pipe(defaultIfEmpty([])),
          this.getStyling(home.styling).pipe(defaultIfEmpty({})),
          this.getCategories(home.categories).pipe(defaultIfEmpty([]))
        )
      )
    );
  }

如果它们是独立的,您可以独立处理它们并在主题上发出它们。

  getAll(): Observable<any> {
    const subject = new Subject<any>();
    const handler = (res: any) => subject.next(res);

    this.getHome().pipe(
      tap((home: Home) => this.application = home),
      tap(handler),
      tap((home: Home) => {
        forkJoin(
          this.getAssets(home.images).pipe(defaultIfEmpty([]),tap(handler))
          this.getStyling(home.styling).pipe(defaultIfEmpty({}), tap(handler))                  
          this.getCategories(home.categories).pipe(defaultIfEmpty([]), tap(handler))
        ).subscribe(res => subject.complete())
      })
    ).subscribe();
    return subject.asObservable();
  }

使用此方法,类型检查必须由使用者完成。

受试者在此记录

我一直在尝试使用merge()而不是combineLatest(),以便收到的每个数据立即发送到父Observable,但显然我不能这样做

听起来好像你正在准备好部分数据。 combineLatest()forkJoin()只有在可以将长度相等的数组填充到可观察数量时才会发出数据。 因此,您要么等待每个observable中的至少一个值,要么等待它们全部完成,但它们会发出一个数组,并且需要知道要放入哪个数组。

我想你想在它准备好后立即发出每一段数据。

首先使用merge()从所有3个observable中发出值,但是对于每个observable使用map()来为该给定类型(图像,样式,类别)创建对象键/值对。

最后,使用scan()运算符将值聚合到单个对象中,该对象将在更新时发出每个属性。

流的消费者可以检查属性是否为null以查看它是否已准备好。 流将在完成之前发出3个值。

  getAll(): Observable<{home: Home, images: any[], styling: any[], categories: any[]}> {
    return this.getHome().pipe(
      tap((home: Home) => this.application = home),
      switchMap((home: Home) =>
        merge([
          this.getAssets(home.images).pipe(
             defaultIfEmpty([]),
             map(images => ({images}))
          ),
          this.getStyling(home.styling).pipe(
             defaultIfEmpty({}),
             map(styling => ({styling}))
          ),
          this.getCategories(home.categories).pipe(
             defaultIfEmpty([]),
             map(categories => ({categories})
          ),
        ]),
        scan((acc, next) => ({...acc, ...next}), {home, images: null, styling: null, categories: null})
      )
    );
  }

如果要发出所有属性为null的第一个值,可以将startWith({})运算符添加到merge()运算符。 作为消费者的早期价值,他们知道其他价值的阅读已经开始。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM