49

在 Angular2 服务中取消订阅 http 订阅的最佳做法是什么?

目前我这样做,但我不确定这是否是最好的方法。

import { Injectable } from "@angular/core";
import { Http } from "@angular/http";

import { Subject } from "rxjs/Subject";
import { ISubscription } from "rxjs/Subscription";

@Injectable()
export class SearchService {
    private _searchSource = new Subject<any>();

    public search$ = this._searchSource.asObservable();

    constructor(private _http: Http) {}

    public search(value: string) {
        let sub: ISubscription = this._http.get("/api/search?value=" + value)
            .map(response => <any>response.json())
            .do(data => this._searchSource.next(data))
            .finally(() => sub.unsubscribe()).subscribe();
    }

}
4

4 回答 4

129

Angular 中的 Service 是一个单例。这意味着该服务将在您的应用程序的整个生命周期中存在。

您需要取消订阅 observable 的原因是为了避免内存泄漏。什么时候出现内存泄漏?如果某些东西在订阅到 observable、事件侦听器、套接字时已经被垃圾回收了,...

由于 Angular 服务永远不会被销毁,除非您的整个应用程序被销毁,否则没有真正的理由取消订阅它。只要您的应用程序执行,observable 将完成或出错或继续运行。

结论:在服务中取消订阅是没有意义的,因为没有内存泄漏的机会。

于 2016-11-30T10:00:40.223 回答
15

我不同意KwintenP 的回答。是的,在可观察到 HttpClient 调用的情况下,无需像Vladimir正确提到的那样取消订阅,但是在其他可观察对象中,您可能肯定需要取消订阅服务。

让我们看一个简单的例子:假设我们有一个发送 observables 的 store,并且在 store 中有一个observable,只要点击鼠标右键就会clicker触发(出于某种奇怪的原因)假设我们有它执行以下操作:trueMyWeirdService

class MyWeirdService {
  doSomethingUnthinkableManyTimes() {
    this.store.select('clicker').subscribe(() => {
      console.log("Hey what do you know, I'm leaking");
    });
  }
}

this.store.select('clicker')返回一个 observable,我们在每次调用时向它注册一个新的处理程序doSomethingUnthinkableManyTimes而不清理它,导致内存泄漏,只要服务存在就会一直存在(在许多情况下是应用程序生命周期)

最重要的是,在上述 Http 的情况下,您不需要取消订阅,因为Vladimir解释得很好,但在其他情况下您可能需要它。

-------------- 版本------------

要在我的示例中解决该问题,只需添加take(1),它会在每个流被触发后自动取消订阅:

class MyWeirdService {
  doSomethingUnthinkableManyTimes() {
    this.store.select('clicker')
     .pipe(take(1))
     .subscribe(() => {
      console.log("What a relief, I'm not leaking anymore");
     });
  }
}
于 2019-08-13T11:22:43.580 回答
7

您不需要取消订阅由Httpor创建的可观察对象,HttpClient因为它是有限可观察对象(值只会发出一次并被complete调用)。

但是,您可以取消订阅由创建的 observableHttpClient取消请求。这意味着您不再对请求返回的数据感兴趣。

于 2019-04-30T17:02:41.973 回答
0

你可以这样做:

You need to understand that the service file should be used to just define the http methods and not subscribe there itself. 
Create the method in the service file, use Dependency injection to inject that service in the component and then use ngOnDesteoy to kill the subscription 

****** this is in your component.ts file *******
// introduce a new subject variable to destroy the subscription
destroy$: Subject<any> = new Subject();

constructor(private serviceName: yoirService){} // Dependency injection 

// wherever you want to unsubsribe an observable or a subscription
this.serviceName.observableName.pipe(takeUntil(this.destroy$)).subscribe(
    // required code 
);

//  use ngOnDestroy() to kill it
ngOnDestroy() {
   this.destroy$.next();
   this.destroy$.complete();
}

This way you'll destroy the service once the component is destroyed. 

于 2021-02-26T04:21:47.953 回答