1

I've read an article which shows an example of 3 async subscriptions to an HTTP request.

@Component({
  selector: 'my-app',
  template: `
    <div>
      <p>{{ (person | async)?.id   }}</p>
      <p>{{ (person | async)?.title   }}</p>
      <p>{{ (person | async)?.body   }}</p>
    </div>
  `,
})
export class App {
  constructor(public http: Http) {
    this.person = this.http.get('https://jsonplaceholder.typicode.com/posts/1')
     .map(res => res.json())
  }
}

I already know that there is no need for an async here and that ReplaySubject can be used and that there are many other solutions , but that's not what I'm after.

The author said that :

The current solution that people suggest:

this.http.get('https://jsonplaceholder.typicode.com/posts/1') .map(res => res.json()).share() ( which is publish().refCount().)

Question:

But re-thinking about publish().refCount() - is it possible that (for some reason) :

  • The first (person | async) has executed the request (refcount=1) and response came back before(!) the last two (person | async)'s subscribed? - this will cause another http request(s) ? I mean - who guarantees that the 3 subscriptions will be available concurrently so that they will all share the same result? is there a possibility for race condition? because i've heard that refcount() is subject to race condition.

  • Besides , When is it considered to be "refcount()>0" ? it that value checked when http is being invoked or is it being checked when response arrives ?

In other words -

sub1 causes refcount()=1 (invoking http). But meanwhile sub2( a second subscription) is made :

  sub1 ———————A—————> http invoked    
   <—————————B———————response

Looking at A & B stages :

When will refcount() will be 2 ? is it on stage A ( before/while http executed) or will subscriptions at stage B will also be considered as refcount()=2 ?

Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • Perhaps `publishReplay` is what you're looking for (see also https://stackoverflow.com/a/37756526/217408) – Günter Zöchbauer Jul 01 '17 at 16:46
  • @GünterZöchbauer Hi thanks, Yeah I know that I can use the last value (via publish replay , or replaysubject/behaviour subject) - But I'm trying to understand if there's a race condition here + when do refcount is calculated . – Royi Namir Jul 01 '17 at 16:48
  • I don't have deep knowledge on Rx. Perhaps someone else. – Günter Zöchbauer Jul 01 '17 at 16:50

1 Answers1

1

That's an interesting question indeed. But I think there are no race condition involved in this piece of code.

The thing is, all the subscription are done synchronously in the template with the async function. Which means, the request will be fired when the first subscription is done indeed, but in the case the server respond before all the other subscriptions are done (if it is even possible), then the main thread will be occupied thus not firing another request when the next subscribe arrives.

Here is a little example I made that tries to reproduce that use case.

const timer = Rx.Observable.of("value")
  .do(() => console.log("start request"))
  .delay(1)
  .do(() => console.log("end request"))
  .publish().refCount()

console.time("sub");
for (var i=0; i < 10; i++) {
  console.log("subscribe" + i)
  timer.subscribe()
}
console.timeEnd("sub")
<script src="https://unpkg.com/@reactivex/rxjs@5.0.3/dist/global/Rx.js"></script>

Here I simulate a request that is responded in 1ms by the server but all the subscriptions take (on my computer at least) around 10ms to complete. So you could say that the response arrives before the subscriptions are all done.

As you can see in the log, the request is fired only once :)

atomrc
  • 2,543
  • 1
  • 16
  • 20
  • I don't understand the test. The loop time is not exceeding the 1 sec – Royi Namir Jul 02 '17 at 20:52
  • Oh, `delay` is taking a number of milliseconds, not seconds. So here it's a delay of `1ms` :) – atomrc Jul 02 '17 at 21:12
  • Re-reading your test , I don't understand wht it suppose to show , of course that there will be only one request becuase the source emits only one event. so ? – Royi Namir Jul 03 '17 at 18:58
  • There will always be one emission. I did some testing and all subscribers _untill emission_ will be counted. That source ( yours and http) was born to emit only one value forever. so I don't understand how I thought to myself that there 's gonna be another request for later subscrivers. – Royi Namir Jul 03 '17 at 19:26