Javascript RxJS——一个可观测的';A';不';t停止发射信号,直到信号从同一个可观测的';A';

Javascript RxJS——一个可观测的';A';不';t停止发射信号,直到信号从同一个可观测的';A';,javascript,rxjs,observable,takeuntil,Javascript,Rxjs,Observable,Takeuntil,我有一个observable,在点击开始按钮后,它每秒向控制台打印一个数字。单击“开始”按钮5秒后,observable应停止打印 启动条件 单击“开始”按钮后的每秒钟 结束条件 单击“开始”按钮五秒钟后 不起作用的代码 const startClick$ = fromEvent(document.getElementById('start'), 'click'); const stop$ = startClick$.pipe(switchMapTo(interval(5000))); cons

我有一个observable,在点击开始按钮后,它每秒向控制台打印一个数字。单击“开始”按钮5秒后,observable应停止打印

启动条件 单击“开始”按钮后的每秒钟

结束条件 单击“开始”按钮五秒钟后

不起作用的代码

const startClick$ = fromEvent(document.getElementById('start'), 'click');
const stop$ = startClick$.pipe(switchMapTo(interval(5000)));
const printInterval$ = interval(1000).pipe(takeUntil(stop$));
const startPrint$ = startClick$.pipe(switchMapTo(printInterval$));

startPrint$.subscribe(
  value => {
    console.log('new value is:', value);
  },
  () => {
    console.log('there was some error!');
  },
  () => {
    console.log('i have completed');
  }
);

stop$.subscribe(() => {
  console.log('i should stop right now!!');
});
单击start按钮五秒钟后,startPrint$Observable不会停止发射

有效的代码

const endClick$ = fromEvent(document.getElementById('end'), 'click');
const stopWithEndClick$ = endClick$.pipe(switchMapTo(interval(5000)));
const printInterval1$ = interval(1000).pipe(takeUntil(stopWithEndClick$));
const startPrint1$ = startClick$.pipe(switchMapTo(printInterval1$));

startPrint1$.subscribe(
  value => {
    console.log('1: new value is:', value);
  },
  () => {
    console.log('1: there was some error!');
  },
  () => {
    console.log('1: i have completed');
  }
);

stopWithEndClick$.subscribe(() => {
  console.log('1: i should stop right now!!');
});
这里我有另一个按钮
end
,我会在单击end按钮5秒后停止。在这种情况下,可观察对象将按预期停止发射


我怎样才能使第一个案例起作用,我在这里犯了什么错误吗?整个工作代码可以在

中找到,这是因为RxJS操作符内部的订阅顺序。第一次单击“开始”按钮时,第一个收到通知的人是
stop$
,但没有人在收听
stop$
,因此通知不会触发任何内容。你看到的是“我应该马上停下来!!”只是因为你在最后订阅了自己

因此,最简单的解决方案是将
stop$
链创建为一个可观察对象,只有在订阅后才会开始发射,就像
timer(5000)
那样,只发射一次,然后完成

const stop$ = timer(5000);
您的最新演示:


请注意,您可能会得到不同数量的结果,因为RxJS(一般的JavaScript)不能保证
5000ms
将恰好是
5000ms
。这同样适用于
1000ms
,因此有时事件可能会以不同的顺序触发。最好使用
take(5)
如果您只想要5个结果。对于日志记录,最好使用例如
点击(v=>console.log(v))
这样您就不会再订阅了。

我这里有一个问题,可观察计时器(5000)将在5秒后发出,但是,我的要求是仅在单击“开始”按钮后启动计时器。我如何实现这一点?另外,当我执行
const stop$=startClick$.pipe(switchMapTo(间隔(5000))时)
startClick$的订阅还没有创建吗?在使用例如
subscribe()
call进行订阅之前,您不会创建订阅。因此
timer(5000)
没有启动计时器,因为还没有人订阅。
startClick$.pipe(switchMapTo(interval(5000))也是如此
-这不会创建订阅。Martin,感谢您抽出时间回复。但是,我仍然感到困惑。1.如果我从另一个按钮而不是同一个按钮管道发送停止间隔,代码是如何工作的,请参阅标题下的代码部分
工作的代码
2。我如何创建一个可观察的在按下“开始”按钮后,at仅发出5秒。@uMar.这是我上面描述的第一个场景,
start$
发出,但没有人订阅了
stop$
,因此,
inverval
Observable从未启动。只需查看源代码并理解您所说的内容。感谢您的解释!``const`printInterval$=interval(1000).pipe(takeUntil(stop$);``这行有一个奇怪的操作,请不要工作。如果修改为像这样使用takeUntil``startPrint$.pipe(takeUntil(stop$))“``在最终订阅中,它与您的链的其他修改一样完美。这不就是在五秒钟后完成外部可观察的吗?我想在单击开始按钮后,每秒在控制台上打印一个数字。