Use RxJS combineLatest to Only Emit Notifications When Certain Events Have Happened

Rares Matei
InstructorRares Matei
Share this video with your friends

Social Share Links

Send Tweet

Having just congratulated us on the very quick and bug-free turn-around of our previous work item, our manager pings us again to tell us that this time, some tasks finish very shortly after our 2 second threshold. So users are still seeing the glitchy spinner behavior. Our new requirement is that once we start showing the spinner, we need to show it for at least 2 seconds, even if there are no more tasks in the background. To solve this, we will create another proxy, this time for the hiding set of events, and use the combineLatest to wait for two events to happen before we can hide the spinner: we actually get the instruction to hide it (no more tasks in the background) and at least 2 seconds have passed.

Instructor: [00:00] But now we have a new problem. If we have a task that lasts just a bit over two seconds, like this one, you'll notice there's a delay but then the spinner quickly appears and disappears again. Let's try it again. It appears and then disappears quickly. We're back to square one of having a glitchy spinner.

[00:19] Our problem stems from the decision to hide the spinner for the first two seconds of activity and only show it after that. If this segment is small, it's going to look glitchy again. Our virtual manager comes in and tells us that once the spinner is showing, keep showing it for at least two seconds.

[00:40] Before jumping in to implement this, let's think about how we can reword it. Once the spinner is showing, when can we hide it? We need to listen for two events in parallel. Have two seconds passed since we started showing it? Check. Did we also get the signal that we have zero tasks remaining and the spinner is inactive?

[01:01] It doesn't really matter in which order these become true. The spinner might get deactivated before the two seconds are up as in the case of the problematic task we just saw, or the two seconds might be reached way before we get the signal to deactivate the spinner as in the case of a really, really long task. If both of these are true, we can hide the spinner.

[01:22] Let's use the space we have at this level of abstraction. The new answer to the question when does the spinner need to hide will be when two events have happened. Spinner became inactive and two seconds have passed. I'll copy this to my code. I'll put it right here at this level.

[01:41] I'll declare shouldHideSpinner and I'll use the combineLatest operator. combineLatest waits for all of its inputs to emit before emitting for the first time. The first event I want to wait for is spinner deactivated and the second is a timer of two seconds. combineLatest is usually used to combine the latest emissions from its inputs and emit them as an array.

[02:08] We don't need the combination capabilities. We're just using it to wait for two separate events to happen before emitting. We've seen this two second timer before. It represents our flash threshold. Anything flashing on the screen for less than two seconds, we consider a bad experience for the user.

[02:25] I'll extract it out and I'll replace it here and here. Now I just need to replace this in our top-level stream. Let's go and test this out. If I trigger the task that takes just a bit over two seconds, and please watch the count of background tasks along with the spinner at the bottom, there will be a small two second delay. The spinner shows and then it hides again.

[02:50] Even though the count of background tasks went to zero, the spinner was still up for the full two seconds that we wanted it to so it's not glitchy anymore. Let's see that again. I'll click this. We wait for a bit. Spinner shows. Tasks go to zero and then the spinner hides. This top one which is really quick continues to work as normal.

[03:10] It doesn't trigger any spinners at all. What's cool is that if we have a really long task like this one, and again please pay attention to both the spinner and the number of tasks we have here, the spinner will wait the obligatory two seconds and then show up, but the moment the tasks go down to zero, the spinner will hide as well. If we have a task that's long enough and wouldn't cause a glitch by ending too quickly, the spinner hides immediately as soon as it's deactivated.

[03:40] To recap, we spend some time to understand and then re-juggle our initial requirement into something that makes a bit more sense. We used combineLatest to wait for two separate events to happen and we created another proxy between events of spinner becoming deactivated and our disposal of the spinner in the top-level stream.