我正在开展一个Angular项目,但我并不完全理解为什么这段代码段没有按预期运行:
const httpObs = Rx.Observable.of("")
.do(() => console.log("trigger http call")) //only triggered once
.publishReplay(1).refCount();
let observable = Rx.Observable.timer(0,1000)
.do((e) => console.log("new event: " + e))
.switchMap(() => this.httpObs);
const c1 = observable.subscribe(() => console.log("subscriber 1"));
const c2 = observable.subscribe(() => console.log("subscriber 2"));
我不明白为什么"触发http电话"不会被Rx.Observable.timer发出的每个事件触发。我的期望是每个发出的事件都会尽快触发http调用,只要一个订阅者订阅了observable。但是,每个用户都接收相同的发射,这意味着每个事件只有一个http呼叫。
我知道我可以通过在observable上使用publishReplay + refcount来修复它(见下文),但这只适用于这个简单的例子。
我真正想要实现的是两个组件使用相同的http调用响应,每个组件发出一个onInit事件,然后switchMapped到http响应。我不希望每个新订阅者都触发该呼叫。但是,我希望在发出另一个事件时触发调用。 onInit observable与click-observable合并,只要用户点击" update"就会发出新事件。按钮,在使用switchMap运算符进行转换之前。问题是,更新按钮不再触发http调用。
此示例显示了它应该如何表现:
const httpObs = Rx.Observable.of("")
.do(() => console.log("trigger http call"));
let observable = Rx.Observable.timer(0,1000)
.do((e) => console.log("new event: " + e))
.switchMap(() => this.httpObs)
.publishReplay(1);
observable.subscribe(() => console.log("subscriber 1"));
observable.subscribe(() => console.log("subscriber 2"))
observable.connect();
答案 0 :(得分:2)
您遇到的问题是所有Subject实例都有其内部状态,当他们收到complete
或error
通知时,他们会将自己标记为“已停止”且永远不会发出任何内容(这是要求)对于所谓的Observable合同)。你可以看一下我前段时间写的这篇文章https://medium.com/@martin.sikora/rxjs-subjects-and-their-internal-state-7cfdee905156。它涉及非常相似的主题。
在您的代码中,您多次使用相同的httpObs
,但源Observable为of()
,会发出单个值,然后发送complete
通知。
看到它真的被称为:http://jsbin.com/fuvuxax/2/edit?js,console
const httpObs = Rx.Observable.of("")
.do(() => console.log("trigger call"), undefined, () => console.log('complete'))
.publishReplay(1).refCount();
这意味着 publishReplay
内的主题收到complete
通知,并且不会再次订阅其来源Observable。但是,由于publishReplay
使用内部ReplaySubject
,它仍将刷新其缓冲区,然后发送complete
通知。但这对你来说并不是很有用,因为我觉得你想再次执行HTTP调用而不只是重放过时的那个。
您可以做的是将httpObs
转换为每次switchMap
收到值时创建链的方法:
const httpObs = () => Rx.Observable.of("")
.do(() => console.log("trigger call"), undefined, () => console.log('complete'));
let observable = Rx.Observable.timer(0,1000)
.do((e) => console.log("new event: " + e))
.take(3)
.switchMap(() => this.httpObs())
.publishReplay(1).refCount();
observable.subscribe(() => console.log("subscriber 1"));
observable.subscribe(() => console.log("subscriber 2"));
你可以看到这只打印"trigger call"
只有三次,如果我理解你的描述,我认为你想要的是:
"trigger call"
"subscriber 1"
"subscriber 2"
"complete"
"trigger call"
"subscriber 1"
"subscriber 2"
"complete"
"trigger call"
"subscriber 1"
"subscriber 2"
"complete"