仅当订阅未共享时 AsyncPipe 初始值为 null

Cal*_*röm 1 rxjs ngrx angular-pipe angular ngrx-store

给定一个看起来像这样的模板

<some-component
  *ngIf="someColdObservable$ | async"
  [result]="someColdObservable$ | async"
></some-component>
Run Code Online (Sandbox Code Playgroud)

和一个看起来像这样的 observable:

someColdObservable$: this.store.pipe(
  select(isAllowedToDoThis),
  filter(Boolean),
  flatMap(() => apiRequest())
);
Run Code Online (Sandbox Code Playgroud)

someColdObservable$被订阅两次(如预期),这反过来问题的两个API调用(这显然是一个代码味道,但让我们无视此刻)。

在这种情况下some-component不包含任何空检查,AsyncPipe如果在模板中评估apiRequest之前没有发出值AsyncPipe导致some-component抛出cannot access x of null(此时[result]仍然为空),则将返回空值,请参阅AsyncPipe参考源

这是所有预期的行为(或至少在阅读源代码之后)但是,当我尝试通过添加shareReplayto来缓解发出两个请求someColdObservable$的问题时,我还解决了[result]apiRequest()发出值之前为 null的问题。这对我来说毫无意义,因为我希望AsyncPipe仍然在null _latestValue这里返回一个,而使cannot access x of null错误未修复。但出于某种原因,添加shareReplay修复了上述两个问题。

这类似于共享时的 Angular 可观察行为奇怪,但仍然存在未解决的问题,即为什么要shareReplay解决此问题。

有人能指出我在这里缺少什么以及为什么在发出值之前AsyncPipe不再返回吗?nullapiRequest()

感谢任何指针和输入,谢谢!

JB *_*zet 6

第一个场景:

  1. 计算 ngIf 表达式。它订阅了 observable 并评估为 null。因此 [result] 表达式不会被计算,因为 ngIf 表达式是假的。
  2. observable 发出,ngIf 表达式变为真。所以 [result] 表达式被评估。它自己的异步管道订阅了冷 observable,它发送另一个请求,并评估为 null,因此作为输入传递给组件。

第二种情况:

  1. 计算 ngIf 表达式。它订阅了 observable 并评估为 null。因此 [result] 表达式不会被计算,因为 ngIf 表达式是假的。
  2. observable 发出,ngIf 表达式变为真。所以 [result] 表达式被评估。它自己的异步管道订阅热 observable,它会立即重放上次发出的内容,并且不再发送请求。因此,表达式被评估为非空值,该值作为输入传递给组件。

比使用 shareReplay 更好的解决方案是将异步管道的结果存储在变量中并使用它:

<some-component
  *ngIf="someColdObservable$ | async as result"
  [result]="result"
></some-component>
Run Code Online (Sandbox Code Playgroud)