Stopping a Stream with TakeUntil

John Lindquist
InstructorJohn Lindquist
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 5 years ago

Observables often need to be stopped before they are completed. This lesson shows how to use takeUntil to stop a running timer. Then we use the starting stream and the stopping stream together to create a simple stopwatch.

[00:00] to stop an observable, let's first make a stop button with a label of stop so we'll have something to click on over here. Then, we can duplicate the query selector, change it to stop, rename it to stop button.

[00:14] Let's start the interval that we already made right away by subscribing to it. We'll log out each tick. We'll hit save. You can see it just starts working automatically without me clicking on anything.

[00:28] To stop this, you might think because subscribe returns a subscription that we could then take the stop button that we already have a reference to, create an observable from event, stop button click.

[00:48] Then whenever we click on this, we'll subscribe to this, we want to get the subscription and unsubscribe. I'll hit "save." You'll see that our timer starts automatically, zero, one, two. I'll hit stop and our timer stops.

[01:06] Again, the way this is working right now is we have an interval, which is an interval of one second. We subscribe to it which returns a subscription. Then, we create an observable from a stop button click. We say when you click unsubscribe from that interval which stops it. Again, this is completely wrong. Do not do it this way.

[01:25] Instead of getting references to subscriptions, you have streams work together. We want it interval that goes until a stop button interval fires. What that looks like, I'll delete this subscribe, and I'll take this observable. I'll cut it.

[01:44] I want this interval to run until which is take until is the operator we'll use. The other observable, I pasted the from event stop button, I want it to run until it gets that click.

[01:57] I'll go ahead and save now. You can see it counts zero, one, two, three. I'll hit stop. The timer stopped. This interval kept on pushing values until it got a stop button click.

[02:11] Let's clean this up a bit. I don't need the subscription anymore. I can extract this a bit. I'll cut this out. I'll call this a stop. Then, I'll just take until stop. When I save, this should work the exact same way with the time running zero, one, two, stop and it stops.

[02:34] Now, if I delete this subscribe, I can get a reference to this observable. We'll call it interval that stops to be very explicit.

[02:45] Now, I can use this as a standalone stream. Subscribe to it and get that same behavior, console log, hit save. We'll get a timer that starts zero, one, two, stop, and it stops.

[03:04] Now that we have this interval that stops stream, let me delete this that we just wrote. I'm going to take our original start interval stream here. I'll cut this and paste it at the bottom. Now, instead of switch mapping to an interval, I'm going to switch map to an interval that stops. I'll hit save.

[03:29] You'll see that the timer doesn't start right away. I'll hit start now. The timer will start. I'll come and click stop. The timer stops. I'll just delete this reference. We don't need it

[03:41] You can read this as a start which is a start button click, which will fire and then switch to an interval that stops. An interval that stops is an interval which is an interval that fires every one second. That will run until a stop button is clicked from stop button click. We have all the pieces put together for a very simple timer that starts and stops...

Alex Krasnicki
Alex Krasnicki
~ 8 years ago

Hi John!

Great series, thanks!

One question: how would you handle a case when start/stop button is the same button?

Alex.

John Lindquist
John Lindquistinstructor
~ 8 years ago

There's a few different approaches depending on the exact behavior you want. Here's one implementation: https://gist.run/?id=1185b7701932b028401b

Alex Krasnicki
Alex Krasnicki
~ 8 years ago

Amazing! Thank you.

nader dabit
nader dabit
~ 8 years ago

For those of you looking for docs or info about switchMap and switchMapTo, it looks like these were added in version 5.0, they were previously known as flatMapLatest -> https://github.com/ReactiveX/rxjs/blob/master/MIGRATION.md

Julia Passynkova
Julia Passynkova
~ 8 years ago

In the lessen 'Stopping a Stream with TakeUntil' I tried to add error and complete handlers to the subscribe call and on complete function was never called when the stop button is clicked. Any idea why?

John Lindquist
John Lindquistinstructor
~ 8 years ago

@Julia - takeUntil will stop the stream it's attached to, so if you want to complete the start$ stream, you would need to move the takeUntil down:

start$
    .switchMapTo(interval$)
    .takeUntil(stop$)
    .subscribe(
      x=> console.log(x),
      err => console.log(err),
      ()=> console.log('complete')

);

Just be aware you'll no longer be able to click the start button, because the start$ is completed.

Julia Passynkova
Julia Passynkova
~ 8 years ago

Thanks a lot. It works. Reading rxjs documentation it is not obvious what is the "complete" behaviour of each operator, especially when multiple streams are combined. Any suggestions?

Rafael Bitencourt
Rafael Bitencourt
~ 8 years ago

Yep, when I started this video, my idea was to simply chain a takeUntil(stop$) on top of what we already had, something like this:

start$
  .switchMapTo(interval$)
  .takeUntil(stop$)
  .subscribe(x => console.log(x));

So I didn't understand when you did something different. It was when I tried it myself that I realized that the code above will take start$ until stop$, so it only worked once. On this case it's really just the interval$ that we want to takeUntil(stop$).

Really enjoying this @John!

Ming
Ming
~ 7 years ago

Hi Thanks for these series , but I couldn't continue watching it and here is why: Almost all of the series which you are the teacher , starts from somewhere unlcear and ends in somewhere unclear. It looks like you've spent a day discovering , while taking videos and talking, Angular2, rxjs, raact and everything and then at the end you've split them in random episodes and chunks. You don't even say hello at the beginning of the course,. you don't even bother introducing yourself, you always start off a function and keep adding stuff to it. Have a look at this one, you start from absolutely no where without even saying hi, and then you continue with takeUntill without giving any context at all. Generally seems like you don't give a f about the listeners and you just want to finish your work. Almost everytime I hear your voice at the beginning of a series, I just stop watching it because I know I need to go and google every single thing you're using. Could you for the love of JavaScript, at least define your start and ending points. Cheers

ganqqwerty
ganqqwerty
~ 6 years ago

Hi Thanks for these series , but I couldn't continue watching it and here is why: Almost all of the series which you are the teacher , starts from somewhere unlcear and ends in somewhere unclear.

I disagree completely. I bought the subscription precisely because I love John's unique style of no-bullshit explanation of the essence of the topic using only one example. I've never seen anything better. I'm here to learn, and to learn fast, not to listen to teacher's greetings and introductions. If I were John I would even encourage other teachers to do the same, that's what unique about egghead compared to other courses and that's what brought a lot of people here.

Markdown supported.
Become a member to join the discussionEnroll Today