如何退订嵌套的可观察对象

时间:2019-12-04 08:52:18

标签: angular typescript rxjs observable

在Angular组件上使用ngOnDestroy()方法,如果http请求在离开页面时仍悬而未决,我们将取消它们。在某些页面上,我们使用自定义的通用缓存助手来防止重新加载已经加载的数据。

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { AsyncSubject } from "rxjs";

@Injectable()
export class HttpCacheHelper {
    public cache = new Map<string, AsyncSubject<any>>();

    public constructor(private readonly http: HttpClient) {        

    }

    public get<T>(url: string): AsyncSubject<T> {
        if (!this.cache.has(url)) {
            const subject = new AsyncSubject<T>();
            this.cache.set(url, subject);
            this.http.get(url)
                .subscribe((data:any) => {
                    subject.next(data as T);
                    subject.complete();
                });
        }
        return this.cache.get(url);
    }
}

如果我取消订阅AsyncSubject,则我的http调用(当然)不会被取消。如何做到这一点?

5 个答案:

答案 0 :(得分:1)

在这种情况下,您不必从http来源退订(请参阅this question)。通常,您可以使用Take运算符或flatmap进行嵌套订阅。

答案 1 :(得分:0)

获取订阅对象并取消订阅。

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { AsyncSubject, Subscription } from "rxjs";

@Injectable()
export class HttpCacheHelper {
    public cache = new Map<string, AsyncSubject<any>>();
    private mySubscription: Subscription;
    public constructor(private readonly http: HttpClient) {        

    }

    public get<T>(url: string): AsyncSubject<T> {
        if (!this.cache.has(url)) {
            const subject = new AsyncSubject<T>();
            this.cache.set(url, subject);
    this.mySubscription = this.http.get(url)
                .subscribe((data:any) => {
                    subject.next(data as T);
                    subject.complete();
                });
        }
        return this.cache.get(url);
    }

// Use below function when required
ngOnDestroy(): void {
    this.mySubscription.unsubscribe();
  }

}

答案 2 :(得分:0)

您需要取消订阅源:

public get<T>(url: string): AsyncSubject<T> {
    if (!this.cache.has(url)) {
        const subject = new AsyncSubject<T>();

        const subscription = this.http.get(url)
            .subscribe((data:any) => {
                subject.next(data as T);
                subject.complete();
            });

         this.cache.set(url, {
           subscribe(observer) { subject.subscribe(observer) },
           unsubscribe(observer) { subscription.unsubscribe() }
         });
    }

    return this.cache.get(url);
}

答案 3 :(得分:0)

您也可以尝试取消订阅

创建我们要用于退订的主题

private onDestroy$ = new Subject();

在您需要取消订阅的任何.subscribe()之前添加此代码

.pipe(takeUntil(this.onDestroy$))

示例

this.anyService.getData()
  .pipe(takeUntil(this.onDestroy$))
  .subscribe((data: any) => {
    // Do work ...
  });

然后像这样使用ngOnDestroy()

ngOnDestroy() {
  this.onDestroy$.next();
  this.onDestroy$.complete(); // Also unsubscribe from the subject itself
}

ngOnDestroy()运行并完成主题后,使用takeUntill进行的任何订阅也会自动退订

答案 4 :(得分:0)

我只会使用publishReplayrefCount

@Injectable()
export class HttpCacheHelper {
  public cache = new Map<string, Observable<yourType>>();

  public constructor(private readonly http: HttpClient) {}

  public get<T>(url: string): Observable<T> {
    if (!this.cache.has(url)) {
      const obs = this.http.get(url).pipe(
         publishReplay(1),
         refCount()
      )

      this.cache.set(url, obs); 
    }

    return this.cache.get(url);
  }

  // Use below function when required
  ngOnDestroy(): void {
    this.mySubscription.unsubscribe();
  }
}