简体   繁体   English

RxJS - 一个 observable 'A' 不会停止发射从同一个 observable 'A' 传送的 takeUntil

[英]RxJS - An observable 'A' doesn't stop emitting with a takeUntil that is piped from the same observable 'A'

I have an observable that prints a number to the console every second after a start button is clicked.我有一个可观察的,在单击开始按钮后每秒向控制台打印一个数字。 The observable should stop printing 5 seconds after the start button is clicked.单击开始按钮 5 秒后,可观察对象应停止打印。

Start Condition every second after the start button is clicked单击开始按钮后每秒开始条件

End Condition five seconds after the start button is clicked点击开始按钮五秒后结束条件

The code that doesn't work不起作用的代码

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!!');
});

After five seconds elapse after clicking the start button, the startPrint$ Observable does not stop emitting.单击开始按钮后五秒钟后,startPrint$ Observable 不会停止发射。

The code that works有效的代码

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!!');
});

Here i have another button end , and i takeUntil 5 seconds after the end button is clicked.在这里,我有另一个按钮end ,我在单击 end 按钮后 5 秒内执行。 In this case the observable stops emitting as expected.在这种情况下,observable 会按预期停止发射。

How can i make the first case work, am I making any mistakes here?我怎样才能使第一个案例工作,我在这里犯了任何错误吗? the entire working code can be found at https://stackblitz.com/edit/take-until-issue?file=index.ts整个工作代码可以在https://stackblitz.com/edit/take-until-issue?file=index.ts 找到

This is happening because of the order of subscriptions inside RxJS operators.发生这种情况是因为 RxJS 运算符中的订阅顺序。 When you first click the "start" button, the first who receives the notification is stop$ but none is listening to stop$ so the notification doesn't trigger anything.当您第一次单击“开始”按钮时,第一个收到通知的是stop$ ,但没有人在收听stop$ ,因此通知不会触发任何内容。 You're seeing "'i should stop right now!!'你看到"'i should stop right now!!' only because you subscribe yourself at the end.只是因为你最后自己订阅了。

So the easiest solution is creating the stop$ chain as an Observable that will start emitting only after you subscribe like timer(5000) that emits just once and then completes.因此,最简单的解决方案是将stop$链创建为一个 Observable,它只会在您订阅后开始发射,例如timer(5000) ,它只发射一次然后完成。

const stop$ = timer(5000);

Your updated demo: https://stackblitz.com/edit/take-until-issue-or4okm?file=index.ts您更新的演示: https://stackblitz.com/edit/take-until-issue-or4okm?file=index.ts

Just be aware, that you might get different number of results because RxJS (JavaScript in general) can't guarantee that 5000ms is going to be exactly 5000ms .请注意,您可能会得到不同数量的结果,因为 RxJS (通常是 JavaScript)不能保证5000ms正好是5000ms The same applies to 1000ms so sometimes the events might be triggered in a different order.这同样适用于1000ms ,因此有时事件可能会以不同的顺序触发。 Better use for example take(5) if you want only 5 results.如果您只想要 5 个结果,则更好地使用例如take(5) Also for logging it's better to use for example tap(v => console.log(v)) so you won't make a another subscription.此外,对于日志记录,最好使用例如tap(v => console.log(v))这样您就不会再次订阅。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM