Angular - 可能的竞争条件 - `publish().refCount()`?
Angular - Possible Race Condition with - `publish().refCount()`?
我读过 article,其中显示了 3 个异步订阅 HTTP 请求的示例。
@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,还有很多其他解决方案,但这不是我所追求的。
作者说:
The current solution that people suggest:
this.http.get('https://jsonplaceholder.typicode.com/posts/1')
.map(res => res.json()).share()
( which is publish().refCount().
)
问题:
但重新考虑 publish().refCount()
- 是否有可能(出于某种原因):
第一个 (person | async)
执行了请求 (refcount=1) 并且响应返回 before(!) 最后两个 (person | async)
订阅了吗? - 这将导致另一个 http 请求?我的意思是 - 谁保证 3 个订阅将 同时 可用,以便它们共享相同的结果?有可能出现竞争条件吗? 因为我听说 refcount() 受竞争条件影响。
此外,什么时候被认为是“refcount()>0
”?它是在 被调用 时检查该值,还是在响应到达时检查该值?
换句话说 -
sub1
导致 refcount()=1
(调用 http)。但与此同时 sub2
(第二次订阅)已完成:
sub1 ———————A—————> http invoked
<—————————B———————response
查看 A
& B
个阶段:
refcount()
什么时候会是2
?它是在 A
阶段(before/while 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/rxjs@5.0.3/dist/global/Rx.js"></script>
这里我模拟了一个服务器在 1ms
中响应的请求,但所有订阅(至少在我的计算机上)需要大约 10ms
才能完成。所以你可以说响应在订阅完成之前到达。
如您在日志中所见,请求仅被触发一次:)
我读过 article,其中显示了 3 个异步订阅 HTTP 请求的示例。
@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,还有很多其他解决方案,但这不是我所追求的。
作者说:
The current solution that people suggest:
this.http.get('https://jsonplaceholder.typicode.com/posts/1') .map(res => res.json()).share()
( which ispublish().refCount().
)
问题:
但重新考虑 publish().refCount()
- 是否有可能(出于某种原因):
第一个
(person | async)
执行了请求 (refcount=1) 并且响应返回 before(!) 最后两个(person | async)
订阅了吗? - 这将导致另一个 http 请求?我的意思是 - 谁保证 3 个订阅将 同时 可用,以便它们共享相同的结果?有可能出现竞争条件吗? 因为我听说 refcount() 受竞争条件影响。此外,什么时候被认为是“
refcount()>0
”?它是在 被调用 时检查该值,还是在响应到达时检查该值?
换句话说 -
sub1
导致 refcount()=1
(调用 http)。但与此同时 sub2
(第二次订阅)已完成:
sub1 ———————A—————> http invoked
<—————————B———————response
查看 A
& B
个阶段:
refcount()
什么时候会是2
?它是在 A
阶段(before/while 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/rxjs@5.0.3/dist/global/Rx.js"></script>
这里我模拟了一个服务器在 1ms
中响应的请求,但所有订阅(至少在我的计算机上)需要大约 10ms
才能完成。所以你可以说响应在订阅完成之前到达。
如您在日志中所见,请求仅被触发一次:)