延迟 Angular 微调器不闪烁
delayed Angular spinner without flickering
目前我正在尝试使用 Angular HttpInterceptor 来显示微调器 once,因此它不会在每次 HttpRequest 完成时闪烁。 interceptor.service.ts 的当前代码如下所示:
@Injectable()
export class InterceptorService implements HttpInterceptor {
constructor(private spinnerService: SpinnerService) {}
showSpinner() {
this.spinnerService.show.next(true);
console.log('true');
}
hideSpinner() {
this.spinnerService.show.next(false);
console.log('false');
}
intercept(
req: HttpRequest<any>,
next: HttpHandler,
): Observable<HttpEvent<any>> {
const responseTimer$ = next
.handle(req)
.pipe(filter(e => e instanceof HttpResponse));
timer(300)
.pipe(takeUntil(responseTimer$))
.subscribe(() => this.showSpinner());
return next.handle(req).pipe(
tap(evt => {
if (evt instanceof HttpResponse) {
this.hideSpinner();
}
}),
);
}
}
但是如果我尝试这段代码,控制台会显示:
interceptor.service.ts:20 true
interceptor.service.ts:25 false
4 x interceptor.service.ts:20 true
4 x interceptor.service.ts:25 false
5 x interceptor.service.ts:25 false
interceptor.service.ts:25 false
但在我看来,它应该是 x 次为真,最后为假。我希望你理解我想要实现的目标。
您的拦截器服务中需要一个计数器,它显示待处理请求的数量。当数字大于 0 时显示微调器。
编辑:
来自文本编辑器的理论
@Injectable()
export class InterceptorService implements HttpInterceptor {
pendingCount$: BehaviorSubject<number> = new BehaviorSubject(0);
constructor(private spinnerService: SpinnerService) {
this.pendingCount$.pipe(
map(Boolean),
distinctUntilChanged(),
).subscribe(
show => this.spinnerService.show.next(show),
);
}
intercept(
req: HttpRequest<any>,
next: HttpHandler,
): Observable<HttpEvent<any>> {
this.pendingCount$.next(this.pendingCount$.value++);
return next.handle(req).pipe(
tap(evt => this.pendingCount$.next(this.pendingCount$.value--)),
);
}
}
更容易创建自己的 Subject
来跟踪已发出的请求数,然后在跟踪计数低于零时通过抛出错误来保护自己免受错误。
class BusySubject extends Subject<number> {
private _previous: number = 0;
public next(value: number) {
this._previous += value;
if (this._previous < 0) {
throw new Error('unexpected negative value');
}
return super.next(this._previous);
}
}
以上是一个主题,它将对加班值求和并进行安全检查以确保低于零。
然后您可以在拦截器中使用它
@Injectable()
export class BusyInterceptor implements HttpInterceptor {
private _requests: BusySubject = new BusySubject();
public get busy(): Observable<boolean> {
return this._requests.pipe(
map((requests: number) => Boolean(requests)),
distinctUntilChanged(),
);
}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this._requests.next(1);
return next.handle(req).pipe(finalize(() => this._requests.next(-1)));
}
}
请务必注意,在上面我使用 distinctUntilChanged()
作为繁忙指示器,还使用 finalize()
作为减少触发器。这些对于跟踪忙碌的正确状态很重要。
以上 应该工作 无论 什么时候 你订阅忙。由于 _previous
值是主体的内部状态。即使没有订阅,它也应该继续正确跟踪。它的工作方式有点像 BehaviorSubject()
,只是它使用 +=
来应用更改。
目前我正在尝试使用 Angular HttpInterceptor 来显示微调器 once,因此它不会在每次 HttpRequest 完成时闪烁。 interceptor.service.ts 的当前代码如下所示:
@Injectable()
export class InterceptorService implements HttpInterceptor {
constructor(private spinnerService: SpinnerService) {}
showSpinner() {
this.spinnerService.show.next(true);
console.log('true');
}
hideSpinner() {
this.spinnerService.show.next(false);
console.log('false');
}
intercept(
req: HttpRequest<any>,
next: HttpHandler,
): Observable<HttpEvent<any>> {
const responseTimer$ = next
.handle(req)
.pipe(filter(e => e instanceof HttpResponse));
timer(300)
.pipe(takeUntil(responseTimer$))
.subscribe(() => this.showSpinner());
return next.handle(req).pipe(
tap(evt => {
if (evt instanceof HttpResponse) {
this.hideSpinner();
}
}),
);
}
}
但是如果我尝试这段代码,控制台会显示:
interceptor.service.ts:20 true
interceptor.service.ts:25 false
4 x interceptor.service.ts:20 true
4 x interceptor.service.ts:25 false
5 x interceptor.service.ts:25 false
interceptor.service.ts:25 false
但在我看来,它应该是 x 次为真,最后为假。我希望你理解我想要实现的目标。
您的拦截器服务中需要一个计数器,它显示待处理请求的数量。当数字大于 0 时显示微调器。
编辑:
来自文本编辑器的理论
@Injectable()
export class InterceptorService implements HttpInterceptor {
pendingCount$: BehaviorSubject<number> = new BehaviorSubject(0);
constructor(private spinnerService: SpinnerService) {
this.pendingCount$.pipe(
map(Boolean),
distinctUntilChanged(),
).subscribe(
show => this.spinnerService.show.next(show),
);
}
intercept(
req: HttpRequest<any>,
next: HttpHandler,
): Observable<HttpEvent<any>> {
this.pendingCount$.next(this.pendingCount$.value++);
return next.handle(req).pipe(
tap(evt => this.pendingCount$.next(this.pendingCount$.value--)),
);
}
}
更容易创建自己的 Subject
来跟踪已发出的请求数,然后在跟踪计数低于零时通过抛出错误来保护自己免受错误。
class BusySubject extends Subject<number> {
private _previous: number = 0;
public next(value: number) {
this._previous += value;
if (this._previous < 0) {
throw new Error('unexpected negative value');
}
return super.next(this._previous);
}
}
以上是一个主题,它将对加班值求和并进行安全检查以确保低于零。
然后您可以在拦截器中使用它
@Injectable()
export class BusyInterceptor implements HttpInterceptor {
private _requests: BusySubject = new BusySubject();
public get busy(): Observable<boolean> {
return this._requests.pipe(
map((requests: number) => Boolean(requests)),
distinctUntilChanged(),
);
}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this._requests.next(1);
return next.handle(req).pipe(finalize(() => this._requests.next(-1)));
}
}
请务必注意,在上面我使用 distinctUntilChanged()
作为繁忙指示器,还使用 finalize()
作为减少触发器。这些对于跟踪忙碌的正确状态很重要。
以上 应该工作 无论 什么时候 你订阅忙。由于 _previous
值是主体的内部状态。即使没有订阅,它也应该继续正确跟踪。它的工作方式有点像 BehaviorSubject()
,只是它使用 +=
来应用更改。