我有一个应用程序,我刚刚在其中添加了NgRX,我希望使用效果来打开和关闭轮询。
样品轮廓
我遵循了this post,这似乎是一个很好的方法。我有一个此here的简化示例,其中大部分代码在app.effects.ts
中。
类似于示例,除了我使用较新的startPolling$
工厂方法外,我还具有stopPolling$
,continuePolling$
和createEffect
的效果。
[此外,我将delay(2000)
移到takeWhile()
上方,因为我发现如果服务调用引发错误,catchError(err => of(appActions.getDataFail(err)))
会导致效果进入连续的非常快速的循环而没有延迟。] >
开始和停止按钮调度轮询开始和停止...
public start() { console.log('dispatching start'); this.store.dispatch(appActions.startPolling()); } public stop() { console.log('dispatching stop'); this.store.dispatch(appActions.stopPolling()); }
我的问题
我有一些控制台日志,所以我们可以看到发生了什么。
当我们单击开始按钮
(恰好是[[第一次时间)时,我可以看到轮询开始,并按预期继续。例如,我可以一遍又一遍地看到以下内容...dispatching start
app effect started polling
app.service.getData
app effect continue polling
app.service.getData
app effect continue polling
app.service.getData
app effect continue polling
完美。
当我停下来时,我看到
dispatching stop
app effect stop polling
也正确。
现在是问题,
是我尝试重新启动时
。如果我现在再次单击开始按钮,那么我看到的只是初始开始轮询效果...dispatching start
app effect started polling
app.service.getData
并且,所以我没有轮询。没有人知道为什么这种效果没有在秒时间内触发吗?我只是不知道为什么会这样。
continuePolling$
中的代码不再被调用
感谢您提供任何信息。
[UPDATE1]
[我想也许我的问题是,一旦isPollingActive
设置为false,并且takeWhile(() => this.isPollingActive),
“停止”,则可观察项将不再处于活动状态,即continuePolling$
完成,因此将永远不会重新启动?[假设是这样,我尝试了以下操作,其中有2个不同的变量,一个变量“暂停”轮询(例如,如果我在离线模式下检测到该应用程序),另一个变量取消(即,当用户导航出该变量时组件)。
所以,我的整个效果现在变成了...
@Injectable()
export class AppEffects {
private isPollingCancelled: boolean;
private isPollingPaused: boolean;
constructor(
private actions$: Actions,
private store: Store<AppState>,
private appDataService: AppDataService
) { }
public startPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.startPolling),
tap(_ => console.log('app effect started polling')),
tap(() => {
this.isPollingCancelled = false;
this.isPollingPaused = false;
}),
mergeMap(() =>
this.appDataService.getData()
.pipe(
switchMap(data => {
return [appActions.getDataSuccess(data)
];
}),
catchError(err => of(appActions.getDataFail(err)))
))
));
public pausePolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.pausePolling),
tap(_ => this.isPollingPaused = true),
tap(_ => console.log('app effect pause polling')),
));
public cancelPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.cancelPolling),
tap(_ => this.isPollingCancelled = true),
tap(_ => console.log('app effect cancel polling')),
));
public continuePolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.getDataSuccess, appActions.getDataFail),
tap(data => console.log('app effect continue polling')),
takeWhile(() => !this.isPollingCancelled),
delay(3000),
mergeMap(() =>
this.appDataService.getData()
.pipe(
delay(3000),
tap(data => console.log('app effect continue polling - inner loop')),
takeWhile(() => !this.isPollingPaused), // check again incase this has been unset since delay
switchMap(data => {
return [appActions.getDataSuccess(data)
];
}),
catchError(err => of(appActions.getDataFail(err)))
))
));
}
我不建议运行上面的命令,因为当我随后分派pause polling action
时,效果似乎陷入无尽的循环,我必须通过任务管理器杀死浏览器。
我不知道为什么会这样,但是我似乎比以前离解决方案还远。
再次提供任何帮助,万分感谢
[UPDATE2]
我注意到我没有从暂停和取消效果中返回任何动作。所以我更新了它们,我们遵循...
public pausePolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.pausePolling),
tap(_ => this.isPollingPaused = true),
tap(_ => console.log('app effect pause polling')),
map(_ => appActions.pausePollingSuccess())
));
public cancelPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.cancelPolling),
tap(_ => {
this.isPollingCancelled = true;
this.isPollingPaused = true;
}),
tap(_ => console.log('app effect cancel polling')),
map(_ => appActions.cancelPollingSuccess())
));
现在暂停似乎可以正常工作,但是当我分派appActions.cancelPolling
时,我再次看到app effect cancel polling
的无限循环被记录到控制台。
[UPDATE3]
我已经找到了为什么得到无限循环以及如何停止它的原因。根据doco here,我可以添加dispatch:false
... public cancelPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.cancelPolling),
tap(_ => {
this.isPollingCancelled = true;
this.isPollingPaused = true;
}),
tap(_ => console.log('app effect cancel polling')),
), { dispatch: false }); // <------ add this
这似乎可以解决我的无限循环。
我现在唯一的任务是能够确定如何启动,停止和重新启动轮询,以处理对appDataService.getData()
的成功调用以及异常处理。
我可以使它适用于任何一个(取决于我放置延迟和时间的地方,但不能同时适用于两者)>
[UPDATE4]
我拥有最新的代码here。按原样运行,我使getData成功,而且令人惊讶的是,无论是pause还是stop动作都会停止它并允许它重新启动。。我很惊讶
stop
动作允许它像我以前那样重新启动假设takeWhile(() => !this.isPollingCancelled),
将取消效果。此外,如果将true
传递给getData
,这将导致它可观察到错误。轮询继续进行(根据需要,即,即使出现错误也要重试),但是一旦我们现在分派暂停动作,它就不会停止轮询,而是分派停止,它确实会停止,但随后不会重新启动。我赢不了。[UPDATE 5]
我想也许是因为继续轮询效果被取消了,所以我可以每次都重新创建它,如下所示。 import { Injectable, OnInit, OnDestroy } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';
import { select, Store } from '@ngrx/store';
import { mergeMap, map, catchError, takeWhile, delay, tap, switchMap } from 'rxjs/operators';
import { AppState } from './app.state';
import { Observable, of } from 'rxjs';
import { AppDataService } from '../app-data.service';
import * as appActions from './app.actions';
@Injectable()
export class AppEffects {
private isPollingCancelled: boolean;
private isPollingPaused: boolean;
constructor(
private actions$: Actions,
private store: Store<AppState>,
private appDataService: AppDataService
) { }
public startPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.startPolling),
tap(_ => console.log('app effect started polling')),
tap(() => {
this.isPollingCancelled = false;
this.isPollingPaused = false;
this.createPollingEffect(); // <--- recreate the effect every time
}),
mergeMap(() =>
this.appDataService.getData()
.pipe(
switchMap(data => {
return [appActions.getDataSuccess(data)
];
}),
catchError(err => of(appActions.getDataFail(err)))
))
));
public pausePolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.pausePolling),
tap(_ => this.isPollingPaused = true),
tap(_ => console.log('app effect pause polling')),
), { dispatch: false });
public cancelPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.cancelPolling),
tap(_ => {
this.isPollingCancelled = true;
this.isPollingPaused = true;
}),
tap(_ => console.log('app effect cancel polling')),
), { dispatch: false });
public continuePolling$: any;
private createPollingEffect(): void {
console.log('creating continuePolling$');
this.continuePolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.getDataSuccess, appActions.getDataFail),
tap(data => console.log('app effect continue polling')),
delay(3000),
takeWhile(() => !this.isPollingCancelled),
mergeMap(() =>
this.appDataService.getData(false)
.pipe(
tap(data => console.log('app effect continue polling - inner loop')),
switchMap(data => {
return [appActions.getDataSuccess(data)
];
}),
catchError(err => of(appActions.getDataFail(err)))
))
), { resubscribeOnError: true });
}
}
因此,在startPolling
中,我叫this.createPollingEffect()
以创建连续轮询效果。但是,当我尝试此操作时,轮询从未开始。
我有一个应用程序,我刚刚在其中添加了NgRX,我希望使用效果来打开和关闭轮询。我在这篇文章之后跟随样本大纲,这似乎是一种不错的方法。我有一个...
public startPolling$ = createEffect(() => this.actions$.pipe(
ofType(appActions.startPolling),
tap(_ => console.log('app effect started polling')),
tap(() => this.isPollingActive = true),
switchMap(() =>
this.appDataSurvice.getData()
.pipe(
exhaustMap(data => {
return [appActions.getDataSuccess(data)];
}),
catchError(err => of(appActions.getDataFail(err)))
))
));