Angular 6多次调用subscribe()可观察

时间:2018-09-19 16:22:44

标签: angular typescript

我有两个组件:NewItemComponent和ListComponent。当我在相应的组件内创建新项目时,我会通知ListComponent以便它可以刷新其数据模型:

export class NewItemComponent implements OnInit {

  constructor(private itemService: ItemService, private notificationService: NotificationService) {
  }

  ngOnInit() {
  }

  createNewItem(item: Item) {
    this.itemService.persist(item).subscribe((response: Item) => {
      console.log(response);
      this.notificationService.notifyNewItemHasBeenCreated(response);
    });
  }
}


export class ListComponent implements OnInit {

  items: Item[];

  constructor(private listService: ListService, private notificationService: NotificationService) {
  }

  ngOnInit() {
    this.loadItems();

    this.notificationService.item$.subscribe((item) => {
      if (item != null) {
        this.loadItems();
      }
    })
  }

  loadItems(){
    this.istService.getItems().subscribe((data: Item[]) => {
      this.items= data;
      console.log(this.items);
    });
  }
}


@Injectable({
  providedIn: 'root'
})
export class NotificationService {

  private _item: BehaviorSubject<Item> = new BehaviorSubject<Item>(null);
  public  item$ = this._item.asObservable();

  constructor() {
  }

  notifyNewItemHasBeenCreated(item: Item) {
    this._item.next(item);
  }
}

让我担心的是 loadItems()多次调用 subscribe()。可以吗?还是有更好的方法根据通知重新获取项目?

  loadItems(){
    this.listService.getItems().subscribe((data: Item[]) => {
      this.items= data;
      console.log(this.items);
    });
  }

ListService返回Observable:

export class ListService {

  basePath = 'my-api.com';
  apiPath = "item";

  constructor(private httpClient: HttpClient) {
  }

  getItems(): Observable<Item[]> {
    return this.httpClient.get<Item[]>(this.basePath + '/' + this.apiPath);
  }
}

提前感谢,我们将不胜感激。

5 个答案:

答案 0 :(得分:3)

作为实验,请执行以下操作:

this.httpClient.get("<some url>")
  .subscribe({
    next: () => {
      console.log("received response")
    },
    error: err => {
      console.log("error occurred")
    },
    complete: () => {
      console.log("subscription completed")
    },
  })

您应该看到:

received response
subscription completed

这意味着每个Web请求的可观察对象在请求完成后即已完成,因此可以安全地取消订阅,因为这是在可观察对象完成时自动完成的。

答案 1 :(得分:1)

编辑:

环顾四周后,我发现了这些帖子:
Is it necessary to unsubscribe from observables created by Http methods?
Prevent memory leaks in Angular 2?

评论和答案说明HttpClient.get()个订阅会在自己清除后清除,因此您无需退订。这意味着多次调用.subscribe()很好。

答案 2 :(得分:1)

loadItems()仅调用一次subscribe
实际上发生的是,您在loadItems()的订阅中多次致电notificationService.item$
如果仅出于此目的需要NotificationService,建议您进行少量重构。

new-item.component.ts

export class NewItemComponent {

  constructor(private itemService: ItemService, private listService: ListService) {
  }

  createNewItem(item: Item) {
    this.itemService.persist(item).subscribe((response: Item) => {
      this.listService.addItem(item);
    });
  }
}

list.service.ts

export class ListService {

  basePath = 'my-api.com';
  apiPath = 'item';

  private itemsSubject: BehaviorSubject<Item[]> = new BehaviorSubject<Item[]>([]);
  private items$: Observable<Item[]>;

  constructor(private httpClient: HttpClient) {
  }

  getItems(): Observable<Item[]> {
    const http$ = this.httpClient.get<Item[]>(this.basePath + '/' + this.apiPath);
    return combineLatest(http$, this.items$).pipe(
      map(([httpResponse: Item[], localItems: Item[]]) => httpResponse.concat(localItems)),
    );
  }

  addItem(item: Item) {
    this.itemsSubject.next([...this.itemsSubject.value, item]);
  }

}

答案 3 :(得分:0)

如果您多次订阅呼叫,则在销毁组件时取消订阅。

要像这样更改组件:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

export class ListComponent implements OnInit, OnDestroy {

  items: Item[];

  constructor(private listService: ListService, private notificationService: NotificationService) {
  }

  subscriptions: Subscription[] = [];

  ngOnInit() {
     this.subscriptions.push(this.loadItems());

     this.subscriptions.push(this.notificationService.item$.subscribe((item) => {
       if (item) {
         this.loadItems();
       }
     }));
  }

  ngOnDestroy() {
    this.subscriptions.forEach(x => x.unsubscribe());
  }

  loadItems(){
    this.istService.getItems().subscribe((data: Item[]) => {
      this.items= data;
      console.log(this.items);
  });
 }
}

答案 4 :(得分:0)

您现在正在做的是:

  1. 制作新商品,发送到服务器
  2. 服务器将带有项目的成功响应发送到项目服务。通知通知服务。您实际上不对此项目做任何事情,但要对其进行验证。
  3. 您的通知服务获取项目,通知您的列表组件。
  4. 您的列表组件检查项目是否有效,然后向服务器发送另一个请求以获取更新的列表
  5. 列表组件为更新的列表订阅列表服务。更新。

因此,简而言之,您对每个新项目都会向服务器发出2个请求,并获得2个响应。

您可以看到这里有很多冗余。让我们尝试简化一下事情:

  1. 制作新商品,发送到服务器
  2. 服务器发送带有更新的项目列表的成功响应。如果收到的商品有效,它将仅发送该商品列表,否则发送回错误响应
  3. 您的通知服务已预订,并获得已由服务器验证的物品清单 ,并将此新物品清单发送给列表服务。
  4. 列表组件使用新数据更新视图。

现在,您每次只发出一个请求,而不是两个。而且您不再需要处理那么多的Observable。