RxJS logo

Sequencing Subscriptions with RxJS

RxJS logo

Let’s say your web-application communicates with a 3rd party service and this service is somewhat fragile. Either because of its fragility – or for some other reason – under no circumstances do you want your application to bombard this service with concurrent requests. Whenever a component needs to make a request to this service, and there is already another request waiting for a response, the new request should wait until the previous request completes.

Normally, in a web-application that uses RxJS (e.g. a modern Angular application), asynchronous requests are represented with instances of Observable. It’s a “single use” Observable that emits a single value—the response—before it completes. Once the Observable is built, the actual request is sent only when the Observable is subscribed, and this is where we need to introduce the new logic: the client code should not care about whether there are any active requests. It should be able to simply create and service request Observable and subscribe to it. However, if an active request against the service exists, sending the request to the service should not execute immediately but be delayed until the other request completes. All of that should happen transparently to the client code. How can it be done?

To implement the above logic with RxJS we can model the process that happens in various places, such as a DMV office, where people have to wait for their turn to go to a window and talk to the person behind it. At the entrance, every visitor gets a ticket with sequential number from a ticket dispensing machine. Then there is a display in the waiting room where the next number is shown. The person whose ticket number matches the number on the display can proceed to the window and be served. Once served, the clerk behind the window pushes the button and the display starts showing the next ticket number. This is exactly what we need, so let’s model it using RxJS:

Now we can call the callService() from anywhere in any order and always be sure that all requests to the service are sent sequentially, the next one only starts once the previous one completes.

Here’s a question for the RxJS experts out there: Is there a better way? (And I’m sure there is — such is the world of RxJS, isn’t it?)