源发出时管道可观察对象不发出

Piped observable not emitting when source emits

public lotId$ = new Subject<number>();

@Input() public set lotId(value: number) {
    this.lotId$.next(value);
};

public results$ = this.lotId$.asObservable().pipe(
    skipWhile(lotId => !lotId),
    switchMap(lotId => this.logicService.getMappedTakeOffTasksForLot(lotId)),
    tap(console.log)
);

在上面的代码中,results$ 不会在每次 lotId$ 发出时发出。有人知道为什么吗?代码在创建组件时运行 results$ 一次,然后再也不会运行。

编辑:源发出 58。

编辑:当我从 Subject 更改为 BehaviorSubject 时它起作用了。为什么?我希望我能早点尝试。

results$ does not emit every time lotId$ emits.

lotId$ 发出之前发生的对 results$ 的订阅将收到这些值。换句话说,迟到的订阅者不会收到先前的值(“迟到的订阅者”我的意思是在发生一些排放后订阅)。

假设您在模板中使用 async 管道,results$ 的订阅在视图初始化之后才会发生,但在此之前会调用 @Input() setter发生了。

您会发现,如果您在构造函数中订阅(只是为了实验),派生的 results$ 实际上会发出初始值。

所以,应该很清楚为什么改成 BehaviorSubject 有效;订阅后,它会向新订阅者发出最新的先前值。

但是,BehaviorSubject 需要默认值(当然会发送给新订阅者)。发出默认值可能并不总是合适的,因此您可以改用 ReplaySubject(1),它也会向新订阅者发出以前的值,但不需要默认值。

下图显示了模板根据使用的主题类型收到的输出 (Subject / ReplaySubject / BehaviorSubject):

如果组件有可选的 @Input(),我使用 BehaviorSubject,因为需要默认值。如果需要输入,我使用 ReplaySubject(1),因此除非消费者提供输入,否则我的逻辑不会执行。

这里有一些 StackBlitz,您可以在其中查看 Angular 生命周期挂钩的顺序以及订阅发生的时间。