嘿,我是rxjs和ngrx的新手,我正在使用这些技术构建应用程序。 我正在考虑如何使用rxjs observables和operator创建一个Polling系统。
我创建了一个基本的轮询系统,其中包含可观察量的订阅地图。每个observable每隔5秒向ngrx-effects发送一个动作,该动作处理动作并执行副作用,例如使用服务进行http调用。
我的问题是我想为当前的池系统创建一个具有以下条件的特定机制:
1.第一个游泳池马上发生,我正在使用计时器(0,poolingTime), 或带有stratwith(null)管道的间隔。
2.池知道根据前一个请求的时间延迟下一个请求。我的意思是当前一个请求完成后,第二个请求就会发生。
我独自实现的第一个分歧,第二个条件(2)我需要帮助才能实现这一目标。 为了完成第二个条件,我强调去抖或踩油门,但正如我先说的那样,我没有很多关于rxjs的经验。
这是我简单汇集系统的代码
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { timer } from 'rxjs/observable/timer';
import { interval } from 'rxjs/observable/interval';
import { throttleTime, debounceTime, startWith, tap, delay } from 'rxjs/operators';
import { Utils } from '../utils';
@Injectable()
export class PoolingService {
private subscriptions: { [id: string]: Subscription };
constructor() {
this.subscriptions = {};
}
public startPooling(time: number, callback: Function): string {
const id = Utils.guid();
const interval$ = interval(time).pipe(tap(tick => console.log("tick", tick))).pipe(startWith(null));
// const interval$ = timer(0, time).pipe(tap(tick => console.log("tick", tick)));
const subscription = interval$.subscribe(() => { callback() });
this.subscriptions[id] = subscription;
return id;
}
public stopPooling(id: string) {
const subscription = this.subscriptions[id];
if (!subscription) {
return;
}
subscription.unsubscribe();
}
}
以下是投票服务的使用:
ngOnInit() {
this.store.select('domains').subscribe((state: any) => {
const { list, lastAddedDomain } = state;
this.markers = list;
this.roots = Utils.list_to_tree(list);
});
this.poolService.startPooling(5000, () => {
this.store.dispatch(new AllHttpActions.HttpActionGet({}, HttpMethods.GET, "/getDomainsForMap", AllDomainActions.FETCH_DOMAINS, Utils.guid()));
});
}
答案 0 :(得分:3)
我可能会尝试这样的事情。我在整个代码中添加了注释,这些注释可以帮助您理解我为什么要做某些事情。
import { Injectable, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import { timer } from 'rxjs/observable/timer';
import { interval } from 'rxjs/observable/interval';
import { startWith, tap, mergeMap, take, takeUntil, filter, map, catchError, delay } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { of } from 'rxjs/observable/of';
import { Subscription } from 'rxjs/Subscription';
@Injectable()
export class PollingService implements OnDestroy {
private destroyed$ = new Subject<any>();
poll<PollResultType>(intervalTime: number, pollFunction: () => Observable<PollResultType>): Observable<any> {
let isRequesting = false;
return timer(0, intervalTime)
.pipe(
// When the service is destroyed, all polls will be unsubscribed from
takeUntil(this.destroyed$)),
tap(tick => console.log('tick', tick))),
// Only continue if isRequesting is false
filter(() => !isRequesting)),
// Set isRequesting to true before requesting data
tap(() => isRequesting = true)),
// Execute your poll function
mergeMap(pollFunction)),
// Set isRequesting to false, so the next poll can come through
tap(() => isRequesting = false)
);
}
ngOnDestroy() {
// When the service gets destroyed, all existing polls will be destroyed as well
this.destroyed$.next();
this.destroyed$.complete();
}
}
// In this example this is a service. But this could also be a component, directive etc.
@Injectable()
export class ConsumerService {
private subscription: Subscription;
private requester: Observable<any>;
constructor(private polling: PollingService, private http: HttpClient) {
// Instead of calling poll and subscribing directly we do not subscribe.
// Like that we can have a requester where we can subscribe to activate
// the polling. You might not need that.
this.requester = this.polling.poll(
500,
// This is our polling function which should return another observable
() => this.http.get('https://cors-test.appspot.com/test')
.pipe(
// Uncomment following line to add artificial delay for the request
// delay(2000),
// Don't forget to handle errors
catchError(error => {
return of('Failed');
})
)
);
// Let's activate our poll right away
this.activate();
}
activate() {
// Deactivate on activation to deactivate any subscriptions that are already running
this.deactivate();
// Subscribe to activate polling and do something with the result
this.subscription = this.requester
// This is for testing purposes. We don't want to overload the server ;)
.pipe(take(10))
.subscribe(res => console.log(res));
}
deactivate() {
if (this.subscription) {
this.subscription.unsubscribe();
this.subscription = undefined;
}
}
}
可能需要注意一些一般事项:
tap(() => ...)
控制台日志语句,可能有助于更好地了解正在发生的事情。我希望这会有所帮助。