Angular 6发送一次请求

时间:2018-09-03 17:31:31

标签: rxjs observable angular6

帮助请解决问题

我正在使用一种方法

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 :(得分:2)

您的问题有点神秘,但我认为您要问的是如何防止重复调用HTTP API。在第一个HTTP调用结束之前,您可能多次在list()上进行观察。您的标志仅在第一次调用完成后才阻止API调用,从而导致不必要的同时调用。

但是不用担心。该缓存要求已经通过ReplaySubject内置在RxJS中,因此您不需要自己实现。 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)完全一样。因此,您创建了一个可连接的可观察对象(is probably not necessary for you)。要从中创建普通的可观察对象,请将其简单地传递到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$;
}

答案 1 :(得分:0)

我们在通过函数共享Observable时遇到两个问题:
-每个函数调用都返回新的Observable(记住该函数)
-可观察的是cold(将“可观察的”转换为“热”)

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');
    }