AsyncPipe 初始值只有在订阅不共享时才为 null

AsyncPipe initial value null only if subscription is not shared

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

<some-component
  *ngIf="someColdObservable$ | async"
  [result]="someColdObservable$ | async"
></some-component>

和一个如下所示的可观察对象:

someColdObservable$: this.store.pipe(
  select(isAllowedToDoThis),
  filter(Boolean),
  flatMap(() => apiRequest())
);

someColdObservable$ 被订阅了两次(正如预期的那样),这又发出了两次 api 调用(这显然是一种代码味道,但让我们暂时忽略它)。

在这种情况下 some-component 不包含任何空检查,如果 apiRequest 在 [=14= 之前未发出值,AsyncPipe 将 return 为空] 在模板中进行计算,导致 some-component 抛出 cannot access x of null(因为此时 [result] 仍然为 null)see AsyncPipe source for reference.

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

这与 类似,但是,shareReplay 解决此问题的原因仍未得到解答。

有人能指出我在这里遗漏了什么以及为什么 AsyncPipeapiRequest() 发出值之前不再 returns null 吗?

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

第一种情况:

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

第二种情况:

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

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

<some-component
  *ngIf="someColdObservable$ | async as result"
  [result]="result"
></some-component>