Angular: 我应该每次需要更新时都订阅http.get()吗?

4

我想知道是否过于频繁地使用了Observable.subscribe()。

在我的组件类中,我有一个名为loadData()的函数。它调用另一个函数this.service.getData(),使用HttpClient.get()向服务器执行HTTP请求。

目前在我的loadData()函数中,我订阅了this.service.getData()的结果。

每当用户单击“更新”按钮时,我都希望调用我的loadData()函数。

问题

  • 如果每次需要执行HTTP请求时都调用我的loadData()函数,那么我会创建多个订阅者吗?
  • 是否存在内存泄漏的风险?
  • 如果有,你知道我该如何重构我的代码吗?

答案

代码示例

private loadData() {
    this.loading = true;
     const subscription = this.service.getData()
      .pipe(
  // console.log() with a delay added for test - START
  map(val => {
    window.setTimeout(() => {
      // This will print true.
      console.log('After delay: Is Subscriber closed?', subscription.closed);
    }, 10);
    return val;
  }),
    // console.log() with a delay added for test - END
    takeUntil(this.ngUnsubscribe))
      .subscribe(data => {
        this.data = data;
        // This will print false.
        console.log('Is Subscriber closed?', subscription.closed);
      },
      error => {
        console.error(error);
        throw error;
      },
      () => {
        this.loading = false;
      });
}
getData(): Observable<DataObject> {
    const uri = encodeURI(this.configService.getUri());
    const headers = new HttpHeaders();
    if (this.pipelineEtag) {
      headers.set('If-None-Match', this.pipelineEtag);
    }
    return this.http.get(uri, {
      headers: headers,
      observe: 'response'
    }).pipe(
      map(resp => this.processResponse(resp)),
      catchError(error => this.handleError(error, this.envProduction))
    );
}

我认为http调用会创建冷的可观察对象,这意味着它们确实为每个新发出的值创建一个新的订阅。你可以存储订阅this.x = this.myService.getData().subscribe(...)并手动取消订阅,或者为你的请求实现缓存系统。 - user4676340
3个回答

2
每次HTTP调用返回一个值,Observable就会完成。因此,在服务中可以放心地执行以下操作。
loadData() { 

    return this.http.get<Data>(dataUrl).pipe(
      //  tap(data => console.log(data)), // eyeball results in the console
      catchError(err => this.handleError(err))
    );

}

并且调用。
this.service.loadData().subscribe((data:Data) => do somthing)

您甚至可以调用exhaustMap或switchMap来控制Observable流,以便不会对服务器进行过多的“提示”


是的,谢谢您的信息。我不知道“tap”的使用方法。我编辑了我的代码以展示如何测试订阅者是否已关闭。 - Kris
实际上,我也在多个组件中对集中式数据服务进行了类似的订阅(数据服务通过http获取数据)。 在我的情况下,我使用httpclient来访问json-server数据库以获取JSON数据。 我注意到的是,每当通过异步管道或组件代码调用subscribe时,都会访问json-service数据库。我可以看到json-server终端在每次访问时更新自身。 那么问题出现了吗? - Zenwalker

0

这是正确的用法,创建多个订阅者没有风险。

来自文档:

AsyncPipe 会自动为您订阅(和取消订阅)。

源代码


技术细节是,一旦 Http 请求完成,observable 的 .complete 方法将被调用,这会终止所有当前的订阅者。这意味着你的订阅者被创建、使用并立即丢弃。

感谢您的评论。因此,我编辑了我的帖子,因为我在另一篇帖子上发现实际上Angular会在进行HTTP请求时自动完成可观察对象。我在这个页面https://angular.io/tutorial/toh-pt6#chaining-rxjs-operators上阅读到,添加的AsyncPipe的价值在于不必使用subscribe(),因为它会自动完成。 - Kris
实际上,我也在集中的数据服务中多次订阅类似的内容(数据服务通过http获取数据)。在我的情况下,我使用httpclient来访问json-server数据库以获取JSON数据。我注意到的是,每当通过异步管道或组件代码调用subscribe时,都会访问json-service数据库。我可以看到json-server终端在每次访问时更新自己。所以有问题吗? - Zenwalker

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接