【问题标题】:Is it possible to "miss" the emission from an observable in this case?在这种情况下,是否有可能“错过”来自可观察对象的发射?
【发布时间】:2021-08-31 03:02:12
【问题描述】:

在工作中,我们经常使用以下模式来响应我们应用程序中的某些事件。

class FooService {
  public doFoo(): void {/* HttpRequest that eventually causes onFoo to emit */}
  public onFoo!: Observable<unknown>;
}

class BarService {
  public doBar(arg: unknown): void {/* HttpRequest that eventually causes onBar to emit */}
  public onBar!: Observable<unknown>;
}

@Component({
  selector: 'foo, [foo]',
  templateUrl: './foo.component.html',
  styleUrls: ['./foo.component.scss'],
})
export class FooComponent implements OnDestroy {
  private fooSubscription: Subscription;
  private barSubscription: Subscription;

  constructor(private fooService: FooService, private barService: BarService) {
    this.fooSubscription = fooService.onFoo.subscribe(this.handleFoo.bind(this));
    this.barSubscription = barService.onBar.subscribe(this.handleBar.bind(this));

    this.fooService.doFoo();
  }

  public models: unknown;

  
  public ngOnDestroy() {
    this.fooSubscription.unsubscribe();
    this.barSubscription.unsubscribe();
  }

  private handleFoo(result: unknown) {
    /* Do some work with result, then trigger next request */
    this.barService.doBar(result);
  }

  private handleBar(result: unknown) {
    /* Do actual work with data */
    this.models = result;
  }
}

注意 1 这始终用作链,因此 handleBar 永远不会被独立调用,事实上,由于某些名为 doBar() 的不相关组件可能会触发它是不希望的行为.

注意 2 我宁愿不碰服务,因为担心它会破坏整个应用程序。

这通常会导致大量订阅和大量样板代码。我想用 rxjs 可观察链替换它,并用 angulars 异步管道绑定数据。我想出了以下代码:

constructor(private fooService: FooService, private barService: BarService) {
  this.modelObservable = this.fooService.onFoo.pipe(
    tap((result) => this.handleFoo(result)),
    concatMap(() => this.barService.onBar),
    tap((result) => this.handleBar(result))
  );

  this.fooService.doFoo();
}

private handleFoo(result: unknown) {
  /* bit of validation on result */

  this.barService.doBar();
}

private handleBar(result: unknown):unknown {/* Do actual work with data and return modified data*/}

所以modelObservable 最终会发出handleBar 返回的值,而异步管道会负责订阅和取消订阅,所以我不必这样做。


但是,我怀疑这是否可行,因为可观察链将调用handleFoo,它会调用doBar() 实际上在concatMap 中订阅onBar。我不喜欢在这里依赖时间或概率。尽管如此,这个解决方案能否奏效?或者是否有可能“错过”来自onBar 的发射?有没有更好的解决方案来获得一个相同的可观察对象?也许另一个 rxjs 运算符(还没有使用那么多)?或者根本不可能将这个过程组合成一个单独的 observable?

【问题讨论】:

  • 你也可以把这个this.barService.doBar();放在pipe()链里面,而不是放在handleFoo()里面
  • @GaurangDhorda 那会改变什么?我真的不知道应该把它放在哪里,请随时在答案中解释:)

标签: angular rxjs


【解决方案1】:

一般来说,我喜欢懒惰地使用 observables...如果你有一个看起来像这样的服务:

class FooService {
  public foo(): Observable<unknown>
}

// When you did `doFoo()`, now you must subscribe
this.fooService.foo().subscribe(this.handleFoo);

那么你在“发送请求”和订阅的同时。

幸运的是,您的服务可以通过使用 defer 轻松适应类似于此模式的内容:

constructor(private fooService: FooService, private barService: BarService) {
  const lazyBarService = defer(() => {
    this.barService.doBar();

    return this.barService.onBar;
  });

  this.modelObservable = defer(() => {
    this.fooService.doFoo();

    return this.fooService.onFoo.pipe(
      tap((result) => this.handleFoo(result)),
      concatMap(() => lazyBarService),
      tap((result) => this.handleBar(result))
    );
  }
}

private handleFoo(result: unknown) {
  /* bit of validation on result */
}

private handleBar(result: unknown):unknown {/* Do actual work with data and return modified data*/}

这将确保您订阅每个 onFoo/onBar 非常接近 doFoo/doBar,因为当有人订阅 observable 时会执行。

我认为这应该足够了,因为这是同步发生的,我假设 doFoo 发送异步操作。否则你必须做一些类似的事情,但首先订阅源,然后执行操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-25
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多