Angular 6 отправить запрос один раз - PullRequest
0 голосов
/ 03 сентября 2018

Помогите пожалуйста решить проблему

У меня есть метод в обслуживании

public list(): Observable<ILanguage[]> {
        return Observable.create((observer: Observer<ILanguage[]>) => {
            if (this._languages && this._languages.length > 0) {
                observer.next(this._languages);
                observer.complete();
            } else {
                this._http.get<ILanguage[]>(this._constants.apiUrl + '/langs').subscribe((allLanguages: ILanguage[]) => {
                    this._languages = allLanguages;
                    observer.next(this._languages);
                    observer.complete();
                });
            }
        });
    }

если вызов метода происходит с задержкой - все работает правильно, запрос отправляется один раз

Но если метод вызывается, почти одновременно - есть несколько запросов

Пытался поставить флаг загрузки, который тоже не работал

public list(): Observable<ILanguage[]> {
        return Observable.create((observer: Observer<ILanguage[]>) => {
            if (this._languages && this._languages.length > 0) {
                observer.next(this._languages);
                observer.complete();
            } else if (!this._requestIsSend) {
                this._requestIsSend = true;
                this._http.get<ILanguage[]>(this._constants.apiUrl + '/langs').subscribe((allLanguages: ILanguage[]) => {
                    this._languages = allLanguages;
                    observer.next(this._languages);
                    observer.complete();
                });
            }
        });
    }

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

У нас есть 2 проблемы с совместным использованием Observable из функции:
- каждый вызов функции возвращает новый наблюдаемый (запоминает функцию)
- Наблюдаемый - холодный (преобразовать наблюдаемый в горячий)

import * as _memoize from 'lodash/memoize';
import { shareReplay } from 'rxjs/operators';

export function ShareReplayObservable(target, key, descriptor) {
  const originalMethod = descriptor.value;
  const getObservableFn = function (...args) {
    return originalMethod.apply(this, args).pipe(shareReplay());
  };

  descriptor.value = _memoize(getObservableFn);

  return descriptor;
}


@ShareReplayObservable
public list(): Observable<ILanguage[]> {
        return this._http.get<ILanguage[]>(this._constants.apiUrl + '/langs');
    }
0 голосов
/ 03 сентября 2018

Ваш вопрос немного загадочный, но я думаю, что вы спрашиваете, как вы можете предотвратить повторный вызов вашего HTTP API. Вы, вероятно, подписываетесь несколько раз на свою list() наблюдаемую до завершения первого HTTP-вызова. Ваш флаг запрещает вызовы API только после завершения первого вызова, вызывая нежелательные одновременные вызовы.

Но не беспокойся. Это требование кеширования уже встроено в RxJS с ReplaySubject, поэтому вам не нужно реализовывать его самостоятельно. ReplaySubject принимает один параметр - количество последних значений, которые должны быть отправлены всем подписчикам при подписке. Просто используйте 1 в качестве значения параметра, и он будет кешировать последнее значение вашей наблюдаемой (я думаю, allLanguages ​​)

Ваш код может быть упрощен до:

private languages$: Observable;

public list(): Observable<ILanguage[]> {
    if (!this.languages$) {
        this.languages$ = new ReplaySubject(1);
        this._http.get<ILanguage[]>(this._constants.apiUrl + '/langs').subscribe((allLanguages: ILanguage[]) => {
            this.languages$.next(allLanguages);
        });
    }
    return this.languages$;
}

Существует даже более чистое и менее обязательное решение, которое включает трубы . Существует канал для обмена наблюдаемыми выбросами с многоадресным объектом. Для кеширования вы можете использовать канал shareReplay(1), который будет вести себя точно так же, как ReplaySubject(1). Тем самым вы создаете подключаемую наблюдаемую (которая , вероятно, вам не нужна ). Чтобы создать из него обычную наблюдаемую, просто направьте ее к refCount(). Результатом, как и выше, являются Observables, которые пересылают последнее кэшированное значение для поздних подписчиков.

private languages$: Observable;

public list(): Observable<ILanguage[]> {
    if (!this.languages$)
        this.languages$ =
            this._http.get<ILanguage[]>(this._constants.apiUrl + '/langs')
                .pipe(shareReplay(1))
                .pipe(refCount());

    return this.languages$;
}
...