forkJoin不触发响应

时间:2019-02-07 07:50:01

标签: rxjs observable

我有以下代码:

    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;
}

每个日志都会返回一个值

1 个答案:

答案 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

由于这看起来像是初始化代码,尽管它在启动时只会被您的应用程序调用一次,所以即使不需要该步骤。