使用 rjxs 而不是 setTimeout 函数订阅的更优雅的方式?

More elegant way to subscribe with rjxs instead of setTimeout function?

我有一个 update() 方法,我用它在 table 和 update/filter 中搜索某些条目,用于输入字段中的每个击键。

我的目标是在每次击键后等待大约 400 毫秒,然后再将请求发送到后端,以避免出现太多无意义的请求。

目前我已经用 setTimeout() 函数实现了它,但我相信 RxJS 有更优雅的方法。

  update(searchInput: string) {
    setTimeout(() => {
      this.myService.search(searchInput)
      .subscribe((res) => {
        this.myArray.content = res;
      });
    }, 400);
  }

有人知道吗?

我在代码中留下了一些评论:

const search = fromEvent(searchInput, 'input').pipe(
  debounceTime(1000), // Time in milliseconds between key events
  distinctUntilChanged(), // If previous query is different from current   
  map(event => event.target.value) // get value,
  filter(query => query) // if character length greater then 0,
  tap(query => console.log(`About to make an API call with query: ${query}`)),
  switchMap(getCars) // Your api call
);

search.subscribe(successCallback);

您可以执行以下操作:

在HTML中:

<input type="text" #myId="ngModel" [(ngModel)]="data" />

在你的组件中:

import {
  debounceTime,
  distinctUntilChanged
} from "rxjs/operators";

@ViewChild('myId', {static: true}) myControl: NgModel;

ngOnInit() {
 this.myControl
  .valueChanges // For each changes
  .pipe(
    debounceTime(400),
    distinctUntilChanged()
   )
  .subscribe(() => ...)

}

尝试使用debounce()distinctUntileChanged():

handleFilterEvent = new Subject<any>();

ngOnInit(){
    this.handleFilterEvent
        .debounceTime(500)
        .distinctUntilChanged()
        .subscribe(value => {
            this.myService.search(searchInput)
                .subscribe((res) => {
                    this.myArray.content = res;
            });
        });
}

onSearchChange(value){
    if(value) {
        this.handleFilterEvent.next(value);
    }
}

HTML:

<input type="text" class="form-control" 
   (input)="onSearchChange($event.target.value)">

您可以使用 fromEventViewchild

来实现

只需引用 ViewChild 如下:

@ViewChild('yourInput') inputName: any;

那么你可以简单地使用:

fromEvent(this.inputName.nativeElement, 'keyup')
            .pipe(
                map((k: any) => k.target.value),
                debounceTime(1000)
            )
            .subscribe(value => {
              foo();
            });

这是真正的 RXJS 方式,我已将 myArray.content 更改为 Observable,因为这样您可以使用管道和映射。这将防止多个请求,更具体地说,它将在开始新搜索之前取消订阅以前的搜索。

searchedInput$ = new Subject<string>();
myArray: { content: Observable<any> } = {};

constructor(myService: any) {
  this.myArray.content = this.searchedInput$.pipe(
    distinctUntilChanged(),
    debounceTime(400),
    switchMap(input => myService.search(input)),
  );
}

update(searchInput: string): void {
  this.searchedInput$.next(searchInput);
}

您要找的是debounceTime。 它在发出任何东西之前等待 x 毫秒。 将它与其他运算符结合使用而不会使您的 API 过载将是一个不错的选择。

您的可观察对象看起来像

const search$ = fromEvent(search, 'input').pipe(
  debounceTime(400), // Wait 400 MS before outputting
  distinctUntilChanged(), // Only output unique values
  map(event => event.target.value), // Extract the value of the search
  switchMap((search) => service.doApi(search)) // SwitchMap to cancel a previous search if it wouldn't have completed
)
search$.subscribe()  // These might leak. Keep them in an array and clean them up when the component unloads

搜索元素将是组件的 viewChild。

import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators';

@Component({
  selector: 'app-component',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
  @ViewChild('yourInput', {static: true}) search: ElementRef;

  searchSubscription: Subscription;

  ngOnInit(): void {
    const search$ = fromEvent(this.search.nativeElement, 'input').pipe(
      debounceTime(400), // Wait 400 MS before outputting
      distinctUntilChanged(), // Only output unique values
      map((event: KeyboardEvent) => (event.target as HTMLInputElement).value), // Extract the value of the search
      switchMap((search) => service.doApi(search)) // SwitchMap to cancel a previous search if it wouldn't have completed
    )  // Lives forever
    this.searchSubscription = search$.subscribe()
  }

  ngOnDestroy(): void {
    this.searchSubscription.unsubscribe()
  }
}