我读过article,其中显示了HTTP请求的3个异步订阅的示例。

@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())
  }
}


我已经知道这里不需要异步并且可以使用ReplaySubject,并且还有许多其他解决方案,但这不是我要的。

作者说:


  人们建议的当前解决方案:
  
  this.http.get('https://jsonplaceholder.typicode.com/posts/1') .map(res => res.json()).share()(即publish().refCount().


题:

但是重新考虑publish().refCount()-是否有可能(由于某种原因):


第一个(person | async)已执行了请求(refcount = 1),并且在最后两个(person | async)已订阅之前返回了响应(!)。 -这会导致另一个http请求吗?我的意思是-谁保证3个订阅将同时可用,以便它们都共享相同的结果?比赛条件是否有可能?因为我听说refcount()受竞赛条件的影响。
此外,什么时候被认为是“ refcount()>0”?是在调用http时检查了该值还是在响应到达时检查了该值?


换一种说法 -

sub1导致refcount()=1(调用http)。但是同时进行sub2(第二个订阅):

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


查看AB阶段:

refcount()什么时候会是2?是在阶段A(执行http之前/期间)还是在阶段B的订阅也将被视为refcount()=2

最佳答案

确实,这是一个有趣的问题。但是我认为这段代码不涉及竞争条件。

事实是,所有预订都使用async函数在模板中同步完成。
这意味着,当第一个订阅确实完成时,该请求将被触发,但是如果服务器在所有其他订阅都完成之前响应(如果可能的话),则主线程将被占用,因此不会触发另一个请求当下一个subscribe到达时。

这是我制作的一个小例子,试图重现该用例。



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/[email protected]/dist/global/Rx.js"></script>





在这里,我模拟了服务器在1ms中响应的请求,但是所有订阅(至少在我的计算机上)都在10ms附近完成。因此,您可以说响应是在所有订阅完成之前到达的。

如您在日志中所见,该请求仅被触发一次:)

10-04 15:18