我有以下代码:
let extension = this._http.Get('/settings/get_kv/credentials', {credential_key : "extensions"})
let urlRef = this._http.Get('/settings/get_kv/credentials', {credential_key : "urlRef"})
let product = this._http.Get('/settings/get_kv/credentials', {credential_key : "product"})
let messageBackend = this._http.Get('/settings/get_kv/credentials', {credential_key : "messageBackend"})
Observable.forkJoin([extension, urlRef, product, messageBackend]).subscribe((results:any) => {
let apikvConfig = {...results[0], ...results[1], ...results[2], ...results[3]};
});
我的getMethos是这样的:
public Get<T>(url, payload): Observable<T> {
let additionalParam = "";
if(payload) {
additionalParam = "?";
for (var key in payload) {
if(additionalParam != "?") additionalParam += "&"
additionalParam += key+"="+payload[key];
}
}
let onGetCompleted = new Subject<any>();
let onGetCompleted$ : Observable<any> = onGetCompleted.asObservable();
this.http.get<T>(url+additionalParam, httpHeaders)
.pipe(
retry(MAX_RETRY)
// TODO add error handler - JP
// catchError()
).subscribe((data) => {
onGetCompleted.next(data);
onGetCompleted.unsubscribe();
})
return onGetCompleted$;
}
但是forkJoin永远不会输入订阅。
我尝试合并,也进行合并,但是他们的摊位返回了我可观察到的结果,而不是结果。
我在做什么错了?
编辑:
我做到了:
Load(): Observable<any>{
let extension = this._http.Get('/settings/get_kv/credentials', {credential_key : "extensions"})
let urlRef = this._http.Get('/settings/get_kv/credentials', {credential_key : "urlRef"})
let product = this._http.Get('/settings/get_kv/credentials', {credential_key : "product"})
let messageBackend = this._http.Get('/settings/get_kv/credentials', {credential_key : "messageBackend"})
extension.subscribe((res) => { console.log(res)});
urlRef.subscribe((res) => { console.log(res)});
product.subscribe((res) => { console.log(res)});
messageBackend.subscribe((res) => { console.log(res)});
let obs = Observable.forkJoin([extension, urlRef, product, messageBackend])
obs.subscribe((results:any) => {
let apikvConfig = {...results[0], ...results[1], ...results[2], ...results[3]};
console.log(apikvConfig);
return;
this._storeApp.dispatch(new StoreUseraction.SetExtensionsValue(apikvConfig));
});
return obs;
}
每个日志都会返回一个值
答案 0 :(得分:1)
首先,为了以后的读者的利益起序(因为我对此有很多了解,所以并没有专门针对您):
90%的时间您不需要主题
实际上,它可能接近99%的时间,因为另外9%的时间将留给编写集成库的人使用。 RxJS的大多数最终用户不需要常规代码中的Subjects
。
现在,这已经解决了您的特定问题。
跳到底部以获得快速答案:)。
您的Get
方法正在尝试重新发明轮子,并且在您的预期行为中引入了错误。
let onGetCompleted = new Subject<any>();
let onGetCompleted$ : Observable<any> = onGetCompleted.asObservable();
this.http.get<T>(url+additionalParam, httpHeaders)
.pipe(
retry(MAX_RETRY)
// TODO add error handler - JP
// catchError()
).subscribe((data) => {
// *** Here is the problem ***
onGetCompleted.next(data);
onGetCompleted.unsubscribe();
})
return onGetCompleted$;
正如@martin在评论中明确提到的,forkJoin
要求每个Observable
至少发射一次并完成。
如果您只是直接从该方法返回使用Observable
创建的this.http.get<T>().pipe()
,则您的代码将按预期工作。但是,由于通过Subject
进行的间接调用,因此从未调用complete
,因此从未执行forkJoin
。
每个调试都订阅工作,因为每个流 都发出一个事件,所以它永远不会完成。 unsubscribe
在RxJS的上下文中意味着取消Observable
,它不会不发送完整或错误信号,从下游角度看,流只是停止,从未完成,事件只是停止出现,并通知订户清除其可能已分配的所有资源。通常,将其视为明确取消订阅的反模式。请参阅:https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87
您可能应该使用
takeUntil
之类的运算符来管理RxJS订阅。根据经验,如果您在单个组件中管理两个或多个订阅,则应该考虑是否可以更好地组合这些订阅。
还要注意,在unsubscribe
上显式调用Subject
还会带来一些额外的危险,因为它会影响Subject
的所有当前和将来的订阅,从而实际上使其无法使用。
让Get
自行管理,而不是用stream
方法来决定生命周期逻辑并可能使自己陷入困境。
public Get<T>(url, payload): Observable<T> {
let additionalParam = "";
if(payload) {
additionalParam = "?";
for (var key in payload) {
if(additionalParam != "?") additionalParam += "&"
additionalParam += key+"="+payload[key];
}
}
return this.http.get<T>(url+additionalParam, httpHeaders)
.pipe(retry(MAX_RETRY))
}
现在,当您使用它时,它应该表现出预期的效果。需要注意的是,在当前的实现中,您似乎试图模仿“仅一次”行为。如果需要保留该行为,则可以通过使用运算符来实现。例如,如果我有两个地方需要同一呼叫的结果,我可以这样做:
const onNext = (loc) => () => console.log(`At ${loc}`);
const source$ = this._http.Get(url, payload).pipe(
tap(onNext('pipe')),
publishLast() // This returns a ConnectableObservable
);
// Sets up both subscriptions
source$.subscribe(onNext('first subscriber'));
source$.subscribe(onNext('second subscriber'));
// Executes the GET call by connecting the underlying subscriber to the source
source$.connect();
// Console
// At pipe
// At first subscriber
// At second subscriber
由于这看起来像是初始化代码,尽管它在启动时只会被您的应用程序调用一次,所以即使不需要该步骤。