可观察订阅不执行

时间:2021-06-07 19:37:02

标签: typescript rxjs observable

我试图一次从列表中显示消息 1 秒。我无法使用 nextMessage() : Observable<any>{ this.currentMessage.next(this.messages[this.messagePointer++]); return this.currentMessages; } subscribeMessage() : void{ this.currentMessage.pipe(switchMap(_=timer(1000).pipe(map(x=>this.nextMessage())))).subscribe(x=>console.log(x)); } ,因为我需要能够在满足条件后立即清除一条消息并显示下一条消息 1 秒。

到目前为止我有

nextMessage

目前这不会产生任何结果。我的想法是,currentMessage 例程每 1 秒更新一次 this.currentMessage.pipe(tap(x=>console.log(x)),switchMap(_=timer(1000).pipe(map(x=>this.nextMessage())))).subscribe(x=>console.log(x)); Observable,如果在两者之间由外部源更新,则 Timer 将被取消并重新启动。 subscribe 方法目前什么都不输出,但是如果我尝试这个

{{1}}

我以 1 秒的间隔从我的数据输出中看到值。为什么点击有效,但订阅无效。

编辑

这是一个指向 StackBlitz Demo

的链接

1 个答案:

答案 0 :(得分:0)

问题:switchMap 在内部 observable 发出之前杀死了 observable。

流程如下:

  1. currentMessage 发出消息
  2. tap 记录该消息
  3. switchMap 启动计时器 (1000)
  4. 当计时器触发时,您调用 nextMessage()
  5. nextMessage 然后将一个值推送到 currentMessage
  6. 在移到 nextMessage 的下一行之前currentMesage 会发出一条消息(与步骤 1 相同)
  7. tap 记录该消息(与第 2 步相同)
  8. switchMap 杀死前一个 observable,并启动一个新的计时器 (1000)
  9. 我们回到nextMessage(),它返回一个可观察对象但它被忽略了,因为它在上一步中被杀死了
  10. 循环回到第 4 步

一个简单的解决方法是将 switchMap 更改为 mergeMap,但不要忘记在内部 observable 上添加一个 take(1),因为您只想拥有一个该 observable 的值:

currentMessage
  .pipe(
    tap(x => console.log('Tap:' + x)),
    mergeMap(_ => timer(1000).pipe(
      map(x => nextMessage()),
      take(1)
    ))
  )
  .subscribe(x => console.log(x));

然而,这很难理解发生了什么......如果你转向一种更具反应性的方法,我认为它会变得更简单。

您说不能使用 interval(1000) 因为您需要根据某些条件进行重置。你为什么不把这个条件作为一个主题,这样你就可以把它写下来?看看这个:

const messageResets = new Subject();

const messages: string[] = ['Message 1', 'Message 2', 'Message 3'];
let messagePointer: number = 0;

console.clear();

messageResets.pipe(
  startWith(null),
  // Every time we need to clear the current message, we just switchMap to a new interval
  switchMap(() => timer(0, 1000).pipe(
    map(() => messages[messagePointer++ % messages.length])
  ))
).subscribe(x => console.log(x));

注意:timer(0, 1000)interval(1000) 相同,但它只是在开始时发出一个值,而 interval 不会。

通常我制作主题只是为了表达流外部的事物:在这种情况下,我希望能够根据我不知道的条件从外部清除当前消息。

但是从长远来看,处理对象以保持某种内部状态总是很痛苦的。