2
votes

Considering I have the following code:

private readonly postAction$ = new Subject();

postStream$ = this.postAction$.pipe(
    exhaustMap(() => {
      this.count ++;
      console.log('fired')
      return of('my other post');
    }),
    startWith(''),
    exhaustMap(()=> {
      this.count ++;
      console.log('fired first')
      return of('my post' + this.count);
    })
  )

Which I subscribe to in my template using the async pipe.

I wasn't expecting this to work, but the output to the console was:

> fired first

Until I call .next() on the postAction$ subject, the first console.log('fired') is never called.

What's the execution context of RxJS operators? How do they work? I would have expected that the first exhaust map needed to emit a value, before the rest of the operators are ran. Couldn't find anything in the rxjs docs

Demo on stackblitz

1

1 Answers

6
votes

I think the best way to find the answer is to actually see what's going on behind the scenes(I haven't done that, but I hope to do so in the future).

Until then, here is how I see things.

Think of a stream as river.
The river is traversed by boats, which basically are the emitted values.
There are also bridges, you can think of them as operators. Each bridge might require some conditions in order to decide which boat can continue its way and which not.

Here is how I'd visualize it:

            The value from `startWith`
                     ↓
~~~~~~~~|~~~~~~~~|~~~B~~~~|~~~~~~~~

        ^        ^        ^
        |        |    `exhaustMap(() => {})`
        |        |
        |   `startWith('B')`
        |
`exhaustMap(() => {})`

The async pipe internally subscribes to(and unsubscribes from) the given observable. I think of the subscription as the process of setting up the river, and the bridges. There are no boats yet.
But, in this case, a boat can start from the second bridge, which means that the first one will have nothing to say about this.

This, if you place the bridges this way:

 postStream$ = this.postAction$.pipe(
    startWith(''),
    exhaustMap(() => {
      this.count ++;
      console.log('fired')
      return of('my other post');
    }),
    exhaustMap(()=> {
      this.count ++;
      console.log('fired first')
      return of('my post' + this.count);
    })
  )

You should see this output in the console:

fired
fired first