Как избежать гонок в Angular 8 - PullRequest
0 голосов
/ 20 сентября 2019

Я реализовал это простое хранилище:

export class BookStore extends Store<BookState> implements OnDestroy {

  private _sub = new Subscription();

  constructor(private api: BookApiService, private data: DataTableService) {
    super(new BookState());
    this._sub.add(this.data.state.subscribe(val => {
      this.fetchBooks(val);
    }));
  }

  fetchBooks(body: any): void {
    this._sub.add(this.api.getBooks(body).subscribe(val => {
      this.setState({
        ...this.state,
        books: val.Data,
      });
    }));
  }

  ngOnDestroy(): void {
    this._sub.unsubscribe();
  }
}

class BookState extends BaseState {
  books: Book[];
}

В конструкторе этого хранилища я подписываюсь на наблюдаемый фильтр данных (объект с различными фильтрами DTO, который изменяется в зависимости от нажатия кнопки пользователем).Проблема в том, что в этом случае возникают гоночные условия.Если я быстро нажимаю на 2 разные кнопки фильтра, иногда данные перезаписываются данными, возвращенными после первого нажатия кнопки (должно быть со второго).

Вот метод getBooks из службы API:

  getBooks(body): Observable<BaseResource<T>> {
    return this.httpClient
      .post<BaseResource<T>>(`${this._host}/${this.base}/${this.name}/getBooks`, body);
  }

Возможно ли сделать эту функцию fetchBooks из конструктора:

this._sub.add(this.data.state.subscribe(val => {
      this.fetchBooks(val);
    }));

Для синхронного выполнения?Я где-то читал, что оператор switchMap - это путь, но я не могу обернуться вокруг него.Может ли кто-нибудь указать мне правильное направление?

Ответы [ 2 ]

1 голос
/ 20 сентября 2019

Посмотрите на switchMap оператора.Он предназначен для игнорирования последнего HTTP-вызова при запуске нового.

Вот пример автоматического завершения ввода со страниц википедии:

this.userInputEvent$.pipe(
                    debounceTime(300), // waits 300ms before calling server, to do only one call when user stops typing
                    distinctUntilChanged(), // do not call server if input did not change since last call
                    switchMap((term: string) => this.wikipediaService.search(term)) // switchs the user-input observable to an http call observable depending on the user input. Ignores last call if a new one is triggered before last one is received.
                ).subscribe(httpResults => this.items = httpResults);
1 голос
/ 20 сентября 2019

Попробуйте это.

  apiSubscription: Subscription;

  fetchBooks(body: any): void {
    if (this.apiSubscription) {
      this.apiSubscription.unsubscribe()
    }
    this.apiSubscription = this.api.getBooks(body).subscribe(val => {
      this.setState({
        ...this.state,
        books: val.Data,
      });
    });
    this._sub.add(this.apiSubscription);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...