簡體   English   中英

如何在 Angular 6 中取消 http 請求?

[英]How to cancel http request in Angular 6?

我有一個包含三個組件的頁面: 1. 產品列表組件,它獲取一些產品作為輸入並顯示它們。 2. Filters 組件,顯示一些過濾器列表,即(大小,顏色,...)並顯示添加的過濾器。 3. Main組件是根組件

假設用戶添加了 1 個過濾器,該過濾器會觸發一個 http 請求以獲取新的過濾產品,並且在請求待處理時他刪除了添加的過濾器,該過濾器會觸發另一個 http 請求以獲取所有產品如何取消第一個請求以便我們不顯示過濾后的產品? 這是我的代碼:

class FiltersService {
  private _filters: any[];

  get filters() {
    return this._filters;
  }
  addFilter(filter) {
    this._filters.push(filter);
  }

  removeFilter(filter) {
    // Remove filter logic ...
  }

}

class DataService_ {
  constructor(private http: HttpClient) {

  }

  getProducts(filters) {
    return this.http.post<any[]>('api/get-products', filters)
  }

}


@Component({
  selector: 'app-main',
  template: `
  <div>
      <app-filters [filtersChanged]="onFiltersChange()"></app-filters>
      <app-products-list [products]="products"> </app-products-list>
</div>
`
})
class MainComponent {
  products: any[];

  constructor(private dataService: DataService_, private filtersService: FiltersService) {

  }

  ngOnInit() {
    this.setProducts()
  }

  setProducts() {
    let filters = this.filtersService.filters;
    this.dataService.getProducts(filters)
      .subscribe(products => this.products = products)
  }

  onFiltersChange() {
    this.setProducts();
  }
}
@Component({
  selector: 'app-filters',
  template: `
  <div>
 Filters : 
 <ul>
     <li *ngFor="let filter of filters" (click)="addFilter(filter)"> {{ filter.name }}</li>
 </ul>

 <hr>
 Added Filters:
 <ul>
 <li *ngFor="let filter of filtersService.filters"> {{ filter.name }}  <button (click)="removeFilter(filter)"> Remove</button></li>
</ul>
</div>

`
})
class FiltersComponent {
  filters = [{ name: 'L', tag: 'size' }, { name: 'M', tag: 'size' }, { name: 'White', tag: 'colour' }, { name: 'Black', tag: 'colour' }]
  @Output() filtersChanged = new EventEmitter()
  constructor(public filtersService: FiltersService) {

  }

  addFilter(filter) {
    const isAdded = this.filtersService.filters.find(x => x.name === filter.name);
    if (isAdded) return;
    this.filtersService.addFilter(filter);
    this.filtersChanged.emit()
  }

  removeFilter(filter) {
    this.filtersService.remove(filter);
    this.filtersChanged.emit()
  }

}

@Component({
  selector: 'app-products-list',
  template: `
  <div>
  <h1>Products</h1>
  <ul *ngIf="products.length">
      <li *ngFor="let product of products">
          {{product.name }}
      </li>
  </ul>
</div>
`
})
class ProductsListComponent {
  @Input() products
  constructor() {
  }

}

長話短說:

處理這種情況的最簡單方法是使用 switchMap 運算符。 這樣做是在新事件出現時立即取消內部訂閱。

一種實現是:

class MainComponent {
  products: any[];
  private _filters$ = new Subject();

  constructor(private dataService: DataService_, private filtersService: FiltersService) {

  }

  ngOnInit() {
    this.setProducts()
  }

  setProducts() {
    this._filters$
        .switchMap((filters)=> this.dataService.getProducts(filters)) // or .let(switchMap...) if you are using rxjs >5.5
        .subscribe(products => this.products = products);
  }

  onFiltersChange() {
    this._filters$.next(this.filtersService.filters);
  }
}

很長的故事:

這里發生的是:當您更改過濾器時,將觸發 onFilterChange。 然后,您通過 _filters$ 主題(主題幾乎與 EventEmitter 相同)發出最新的過濾器(在 this.filtersService.filters 內)。

回到組件初始化期間,ngOnInit 方法調用了 setProducts,它已經為未來事件訂閱了 _filters$ 主題(此時沒有發生)。 當事件到達 _filters$ 時,我們會觸發數據服務的 getProducts 方法,將事件中包含的過濾器傳遞給它。 我們將在此行等待,直到 http 調用完成。 一旦完成,http 調用的結果將被分配給組件的產品。

如果在我們等待 http 響應返回時,onFiltersChange 再次被觸發,那么一個新事件將到達 switchMap 並且它將取消之前的 http 請求,以便它可以處理新事件。

這是一種非常強大的方法,因為更改單個運算符,您可以輕松更改應用程序的行為。 例如,將 switchMap 更改為 concatMap 將使請求等待前一個請求完成(將連續發生)。 將其更改為 flatMap 將具有與您發布的原始代碼相同的行為(http 請求將在過濾器更改后立即發生,而不會影響以前的請求,響應順序將不可預測)等等。

注意:取消請求只需使用取消訂閱。

例如

   const course$ = this.service$.getCourses(`/api/courses`).subscribe(courses => { console.log(courses) }

   setTimeout(() => course$.unsubscribe(),1000) // cancel the request

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM