Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.0k views
in Technique[技术] by (71.8m points)

angular - How to make same http call on load and on keyup

In my application i have a modal with a list and an input search field. The modal is invoked on button click in parent component which calls the public function inside the modal component that fetches the list item.Also, whenever user types in the search bar, again the same http request is made to get all the data having the search value since all data has not been loaded at once.

For search input, i'm using subject which emits value on keyup.

public showModal(msg) {
  this.headMsg = msg;
  this.loadList();
}
loadList() {
  this.onListUpdate(this.getList(""));
}
getList(param: string) {
  this.loader = true;
  return this.httpService.getProducts(param);
}
onListUpdate(list$: Observable<any>) {
  list.subscribe((response: any[]) => {
    if(response) this.items = response;
  },
  error => console.log(error),
  () => this.loader = false
 )
}

input keyup

 this.filterChanged.next(searchTerm);
onSearchFieldChanged() {
    let item$ = this.filterChanged.pipe(
      debounceTime(this._debounceTime),
      distinctUntilChanged(),
      switchMap(term => {
        return this.getList(term).pipe(
          tap(() => {
            this.loader = false;
          })
        );
      })
    )
    this.onListUpdate(item$);
  }

Is there a better way to handle the list update functionality?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I would improve the performance issue that you have.

User can search the same thing a lot of times and in your case for the same string you are calling a new API, but the result will be the same.

In this case, I recommend adding caching already used API with the same string.

What we can do?

we can use shareReplay in combination with Map for your getList method.

I made an example of how it will look:

import { Component } from "@angular/core";

import { mergeMap, exhaustMap, concatAll, shareReplay } from "rxjs/operators";
import { HttpClient } from "@angular/common/http";
import { from, Observable, Subject } from "rxjs";

@Component({
  selector: "my-app",
  template: `
    <input
      type="number"
      min="1"
      max="10"
      (keyup)="onInputChange($event.target.value)"
    />
  `,
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  private readonly products = new Map<string, Observable<any>>();
  constructor(private http: HttpClient) {}
  ngOnInit() {}
  onInputChange(value) {
    console.log(value);
    this.getList(value).subscribe();
  }

  getList(param) {
    // this.loader = true;
    const cacheKey = param;
    if (!this.products.get(cacheKey)) {
      this.products.set(
        cacheKey,
        this.http
          .get("https://jsonplaceholder.typicode.com/todos/" + param)
          .pipe(shareReplay(1))
      );
    }

    return this.products.get(cacheKey);
  }
}


In accordance with the screeshot in your case, Based on your code you will have 7 API call!!!

In console, you can see set of user input 1, 12, 123, 12, 1, 12, 123 You will have:

  • two calls of API for - 1
  • two calls of - 123
  • and tree call of = 12

Yes, I saw that you added debounceTime and distinctUntillChanged - but the issue still exists

and we can reduce it to 3 unique API calls

enter image description here

So, Each searchable string we will store in Map as key, and API with shareReaplay (to avoid duplicate call API) as value. And each time when we want call product we will check if API already exist in Map and if exist we will return the already used API

    if (!this.products.get(cacheKey)) {
      this.products.set(
        cacheKey,
        this.http
          .get(url + param)
          .pipe(shareReplay(1))
      );
    }

    return this.products.get(cacheKey);

You can try it in: https://stackblitz.com/edit/angular7-rxjs-cz6pcs?file=src/app/app.component.ts


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...