【问题标题】:Angular2: Unsubscribe from http observable in ServiceAngular2:取消订阅服务中的http observable
【发布时间】:2017-04-13 04:33:47
【问题描述】:

在 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();
    }

}

【问题讨论】:

  • 在 observable 完成时取消订阅似乎是多余且毫无意义的。
  • @günter-zöchbauer 好吧,我的问题不是我的问题,我的问题是:最佳实践是什么。那么?
  • 我认为对于没有意义的事情没有最佳实践:D 也许只是 - 不要这样做。
  • 我不应该做什么? @günter-zöchbauer 也许一个解释会比无用的 cmets 更好

标签: angular rxjs5 unsubscribe


【解决方案1】:

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

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

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

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

【讨论】:

  • 感谢@kwintenp 的回答。但正如您在上面看到的,每次调用 search 方法都会创建一个新的 observable,我必须订阅它才能获取数据。我不是必须取消订阅以避免内存泄漏吗?
  • 没关系。返回的每个订阅都会自行清理。 HTTP 服务会自行清理。当收到 XHR 结果时,订阅的 complete 方法会被调用,因此会自行取消订阅。但是,可能会在 http 服务返回的 Observable 上调用 unsubscribe 方法。如果我们想取消正在进行的 HTTP 请求,我们会调用 unsubscribe。这会在后台调用 abort 以完成清理工作。
  • “该服务将在您的应用程序的整个生命周期中存在”不是真的。我可以只为组件的生命周期提供服务,这样当组件被销毁时它就会被销毁......
  • “结论:取消订阅服务是没有意义的,因为没有内存泄漏的可能性。”我认为更准确的说法是不需要取消订阅由 Angular 的 http 服务创建的 observables。可能存在由两个组件共享的服务引用订阅内的某个对象的情况。如果该共享服务被垃圾收集(请参阅上面的@MarkusE. 评论),您最终可能会出现内存泄漏。
  • 我知道这是一个旧线程,但我想添加这个因为我来到这里寻求有关如何在服务中的可观察对象不是单例时取消订阅的信息(特别是)。我坚持将 observable 作为响应接口的一部分返回的格式,以便调用组件能够随时取消订阅它。希望这会有所帮助。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    您不需要取消订阅 HttpHttpClient 创建的 observable,因为它是有限的 observable(值只会发出一次,complete 会被调用)。

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

    【讨论】:

      【解决方案4】:

      你可以这样做:

      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. 
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-17
        • 2020-08-29
        • 2019-03-19
        • 2018-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多