动态控制的可观察间隔

时间:2019-07-03 21:38:05

标签: angular rxjs observable

在我的网站上,我有一个名为“自动刷新”的全局下拉列表,可让您选择一个轮询间隔: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 个答案:

答案 0 :(得分:1)

由于您的持续时间会随着时间而变化,因此我们可以使用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

希望它能为您解决问题提供一个思路。

答案 1 :(得分:0)

通过对@ 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))
            );
        })
    );
}