Динамически контролируемый наблюдаемый интервал - PullRequest
0 голосов
/ 04 июля 2019

На моем веб-сайте у меня есть глобальное раскрывающееся меню «Автообновление», которое позволяет вам выбрать интервал опроса: 0, 1, 2, 3 и т. Д., И при выборе этого параметра HTTP-API текущей страницы будут опрашиваются каждые 0, 1, 2, 3 секунды и т. д.

Пока у меня есть это:

import { Injectable, Output, EventEmitter } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Rx';

@Injectable()
export class ApiService {
    private interval: number = 0;

    constructor(private http: HttpClient) { }

    autoRefreshObservable() {
        if (this.interval > 0)
            return Observable.timer(this.interval * 1000);

        return Observable.timer(999999999999999);
    }

    getApi(url: string) {
        return Observable.of(null)
                .switchMap(e => this.autoRefreshObservable())
                .flatMap(() => this.http.get(url))
                .repeat();
    }

    updateInterval(i: number) {
        this.interval = i;
    }
}

И если я вызываю что-то вроде this.apiService.getApi("/api/foo").subscribe(response => {...}) в компоненте, это работает ... вроде. Если вы когда-нибудь установите автообновление на 0, оно больше не будет работать, пока вы не обновите страницу. Кроме того, я хочу, чтобы он немедленно возвращал первый ответ, но затем ожидал интервал для последующих ответов.

Это вообще возможно сделать изнутри сервиса? Или я должен перенести эту логику в компоненты, использующие ее?

Дело в том, что есть много компонентов, и добавление поддержки автоматического обновления для каждого из них потребует большого количества шаблонов; вот почему я надеялся перенести логику в общий сервис.

Ответы [ 2 ]

1 голос
/ 04 июля 2019

Поскольку ваша продолжительность меняется с течением времени, мы можем сделать интервал наблюдаемым, используя BehaviourSubject.Сказав это, давайте обновим ApiService следующим образом -

    export class ApiService {    

    interval$: BehaviorSubject<number> = new BehaviorSubject<number>(0);

    getApi(url: string) {

        return this.interval$
                   .pipe(
                       switchMap(duration => {

                            //From your current code (Observable.timer(999999999999999);), it appears that on duration 0
                            //You do not want to call API; So this check will take care of that
                            if (duration === 0) {
                                //lets not emit anything; i.e. wait for the a NON zero duration
                                return NEVER;
                            }

                           return interval(duration * 1000)
                                  .pipe(
                                      switchMap(() => this.http.get(url))                                      
                                  );
                       })
                   );
    }

    updateInterval(i: number) {
        this.interval$.next(i);
    }
}

См. Рабочий пример [всего лишь симуляция] - https://stackblitz.com/edit/angular-pi3uaz?file=app%2Fapi.service.ts

Надеюсь, это даст вам решение вашей проблемы.

0 голосов
/ 05 июля 2019

С некоторыми изменениями в ответе @ user2216584 я получил именно то, что хотел:

getApi(url: string) {
    return this.interval$
    .pipe(
        switchMap(duration => {
            if (duration === 0)
                return this.http.get(url);

            return interval(duration * 1000).startWith(0).pipe(
                switchMap(() => this.http.get(url))
            );
        })
    );
}
...