Combined with RXJS to achieve efficient HTTP requests

In projects, it is common to encounter the need for users to enter data in the input field, call the background API in real time, and duplicate the input based on the results, or search.

Let’s use Github’s user search API as an example.

@Component({
  template: `  
      
  • {{user.login}}
`
}) export class HttpRequestComponent { constructor(private httpClient: HttpClient){}userList: any[] = []; // Search and render to the current page search(name: string) :void { this.sendSearchRequest(name) .subscribe(res= > { this.userList = res.items; }); } // Send a search request sendSearchRequest(name): Observable<{items: any[]} > {return this.httpClient.get<{items: any[]} > ('https://api.github.com/search/users?', { params: { q: name } }); }}Copy the code

The above code is sufficient to fulfill the requirements, but there are several pitfalls.

  1. The request is inefficient, if I outputneteaseSo because of the change in input,n.ne.net.neteaseA total of 7 requests will be made. Actually, just one last timeneteaseResults.
  2. The resulting response time of multiple requests is not controllable, and thus the rendering results are not controllable. Assumption number onenThe search request takes 10s to respond, while other requests containneteaseThe search only takes 1s, and the final rendering result of the page is n search results, which is obviously not correct.

There are several operators needed to solve the above problem:

export class HttpRequestComponent implements OnInit {

  constructor(private httpClient: HttpClient){}userList: any[] = [];

  / / search subject
  private onSearch$: Subject<string> = new Subject();

  search(name: string) :void {
    // Each input produces a value
    this.onSearch$.next(name);
  }

  private sendSearchRequest(name): Observable<{items: any[]} > {return this.httpClient.get<{items: any[]} > ('https://api.github.com/search/users?', {
      params: {
        q: name
      }
    });
  }

  ngOnInit(): void {
    // Subscribe to search$at initialization to update page search results.
    this.onSearch$.asObservable()
      .pipe(
      	// Pay attention to the order
        / / image stabilization
        debounceTime(1000),
        // Change is required
        distinctUntilChanged(),
        // Map to a new Observable
        switchMap(name= > this.sendSearchRequest(name))
      )
      .subscribe(res= > {
        this.userList = res.items; }); }}Copy the code
  • Subject has a dual nature. It has both Observer and Observable behavior. (Mainly used for communication between components)

    / / send the value
    subject.next( 2 )
    / / subscription
    const subscription = subject.subscribe( (value) = > console.log(value) )
    Copy the code
  • DebounceTime A common anti-shake policy on the front-end. Only the last value is retained within a certain period of time.

    When the user input continuously within 1000ms, we only make the request for the last input, which greatly improves the request efficiency.

  • DistinctUntilChanged will update only if the value changes. Only content changes trigger the request.

    Some browsers may repeatedly trigger input events when the input value remains the same

  • SwitchMap is somewhat similar to Promise. The actual effect is to complete the previous Observable and map it to a new Observable.

    In practice, in Angular, this operator causes the previous request to be cancelled in the repeated request scenario described above, such as a search, page-turning, and so on, which ensures the order of requests and results.