如果在 1 秒内没有响应,如何添加到数组?
How to add to array if no response during 1 second?
我有一个监听器 requests/responses。
我曾尝试 运行 仅当请求超过 1 秒时才使用微调器:
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
private requests: HttpRequest<any>[] = [];
constructor(private spinnerService: SpinnerService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
this.requests.push(req);
this.spinnerService.isLoading.next(true);
return new Observable((observer) => {
next.handle(req).subscribe(
(event) => {
if (event instanceof HttpResponse) {
this.removeRequest(req);
observer.next(event);
}
},
() => {
this.removeRequest(req);
},
() => {
this.removeRequest(req);
}
);
});
}
private removeRequest(request: HttpRequest<any>) {
const index = this.requests.indexOf(request);
if (index >= 0) {
this.requests.splice(index, 1);
}
this.spinnerService.loadingStop.next();
this.spinnerService.loadingStop.complete();
this.spinnerService.isLoading.next(this.requests.length > 0);
}
}
旋转器服务是:
constructor() {
this.isLoading
.pipe(debounceTime(100), delay(1000), takeUntil(this.loadingStop))
.subscribe((status: boolean) => (this.loadingStatus = status));
}
为此我添加了这个:
.pipe(debounceTime(100), delay(1000), takeUntil(this.loadingStop))
但这对我不起作用...如果响应超过 1 秒,如何显示微调器?
使用 iif 运算符立即停止加载。
拦截器应该是这样的:
constructor(private spinnerService: SpinnerService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.spinnerService.start(request.url);
return next.handle(request).pipe(
finalize(() => () => this.spinnerService.stop(request.url))
);
}
这是加载服务:
@Injectable()
export class SpinnerService {
private _loading: BehaviorSubject<boolean>;
private _request: Set<string>;
private _delayTime: number;
constructor() {
this._loading = new BehaviorSubject(false);
this._request = new Set();
this._delayTime = 1000;
}
isLoading(time?: number): Observable<boolean> {
return this._loading.asObservable().pipe(
// uses switchMap to cancel the previous event
switchMap(isLoading =>
// use iif to put delay only for true value
iif(
() => isLoading,
of(isLoading).pipe(
delay(time !== undefined ? time : this._delayTime),
),
of(isLoading),
),
),
);
}
start(request: string = 'default', delayTime?: number): void {
if (delayTime !== undefined)
this._delayTime = delayTime;
this._request.add(request);
this._loading.next(true);
}
stop(request: string = 'default'): void {
this._request.delete(request);
if (!this._request.size)
this._loading.next(false);
}
}
所以它应该在模板中查找
@Component({
selector: 'my-app',
template: `<div *ngIf="isLoading$ | async">loading...</div>`,
})
export class AppComponent {
isLoading$: Observable<boolean>;
constructor(private spinnerService: SpinnerService) {
this.isLoading$ = this.spinnerService.isLoading();
}
}
为了防止加载指示灯闪烁(我省略了对多个请求的处理)。
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(private spinnerService: SpinnerService) {}
intercept(req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> {
this.spinnerService.start();
return next.handle(req).pipe(finalize( () => this.spinnerService.stop()));
}
}
旋转器服务中的 debounceTime(500) 可以解决问题:
export class SpinnerService {
private readonly state = new BehaviorSubject<boolean>(true);
readonly state$ = this.state.asObservable()
.pipe(
debounceTime(500),
distinctUntilChanged()
);
constructor() {}
public start() {
this.state.next(true);
}
public stop() {
this.state.next(false);
}
}
要查看此操作的组件:
export interface Post {
id: string;
title: string;
body: string;
}
@Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.css'],
})
export class PostsComponent implements OnInit {
readonly posts$: Observable<Post[]> = this.httpClient
.get<Post[]>('https://jsonplaceholder.typicode.com/posts')
.pipe(shareReplay(1));
readonly state$ = this.spinnerService.state$;
constructor(
private spinnerService: SpinnerService,
private httpClient: HttpClient
) {}
ngOnInit() {}
}
HTML:
<p>List of Posts</p>
<ng-container *ngIf="(state$ | async); else printResult">
<h1>Loading...</h1>
</ng-container>
<ng-template #printResult>
<ng-container *ngIf="posts$ | async as posts">
<p *ngFor="let post of posts">
{{ post.title }}
</p>
</ng-container>
</ng-template>
通过拦截器的解决方案有些粗粒度。在某些时候,您可能需要更细粒度的解决方案。例如。显示多个并行 requests/components 的加载指示器。 Nil's blog post中给出了另一种解决方案。
您的问题有很多解决方案。希望对你有帮助。
我有一个监听器 requests/responses。
我曾尝试 运行 仅当请求超过 1 秒时才使用微调器:
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
private requests: HttpRequest<any>[] = [];
constructor(private spinnerService: SpinnerService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
this.requests.push(req);
this.spinnerService.isLoading.next(true);
return new Observable((observer) => {
next.handle(req).subscribe(
(event) => {
if (event instanceof HttpResponse) {
this.removeRequest(req);
observer.next(event);
}
},
() => {
this.removeRequest(req);
},
() => {
this.removeRequest(req);
}
);
});
}
private removeRequest(request: HttpRequest<any>) {
const index = this.requests.indexOf(request);
if (index >= 0) {
this.requests.splice(index, 1);
}
this.spinnerService.loadingStop.next();
this.spinnerService.loadingStop.complete();
this.spinnerService.isLoading.next(this.requests.length > 0);
}
}
旋转器服务是:
constructor() {
this.isLoading
.pipe(debounceTime(100), delay(1000), takeUntil(this.loadingStop))
.subscribe((status: boolean) => (this.loadingStatus = status));
}
为此我添加了这个:
.pipe(debounceTime(100), delay(1000), takeUntil(this.loadingStop))
但这对我不起作用...如果响应超过 1 秒,如何显示微调器?
使用 iif 运算符立即停止加载。
拦截器应该是这样的:
constructor(private spinnerService: SpinnerService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.spinnerService.start(request.url);
return next.handle(request).pipe(
finalize(() => () => this.spinnerService.stop(request.url))
);
}
这是加载服务:
@Injectable()
export class SpinnerService {
private _loading: BehaviorSubject<boolean>;
private _request: Set<string>;
private _delayTime: number;
constructor() {
this._loading = new BehaviorSubject(false);
this._request = new Set();
this._delayTime = 1000;
}
isLoading(time?: number): Observable<boolean> {
return this._loading.asObservable().pipe(
// uses switchMap to cancel the previous event
switchMap(isLoading =>
// use iif to put delay only for true value
iif(
() => isLoading,
of(isLoading).pipe(
delay(time !== undefined ? time : this._delayTime),
),
of(isLoading),
),
),
);
}
start(request: string = 'default', delayTime?: number): void {
if (delayTime !== undefined)
this._delayTime = delayTime;
this._request.add(request);
this._loading.next(true);
}
stop(request: string = 'default'): void {
this._request.delete(request);
if (!this._request.size)
this._loading.next(false);
}
}
所以它应该在模板中查找
@Component({
selector: 'my-app',
template: `<div *ngIf="isLoading$ | async">loading...</div>`,
})
export class AppComponent {
isLoading$: Observable<boolean>;
constructor(private spinnerService: SpinnerService) {
this.isLoading$ = this.spinnerService.isLoading();
}
}
为了防止加载指示灯闪烁(我省略了对多个请求的处理)。
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(private spinnerService: SpinnerService) {}
intercept(req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> {
this.spinnerService.start();
return next.handle(req).pipe(finalize( () => this.spinnerService.stop()));
}
}
旋转器服务中的 debounceTime(500) 可以解决问题:
export class SpinnerService {
private readonly state = new BehaviorSubject<boolean>(true);
readonly state$ = this.state.asObservable()
.pipe(
debounceTime(500),
distinctUntilChanged()
);
constructor() {}
public start() {
this.state.next(true);
}
public stop() {
this.state.next(false);
}
}
要查看此操作的组件:
export interface Post {
id: string;
title: string;
body: string;
}
@Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.css'],
})
export class PostsComponent implements OnInit {
readonly posts$: Observable<Post[]> = this.httpClient
.get<Post[]>('https://jsonplaceholder.typicode.com/posts')
.pipe(shareReplay(1));
readonly state$ = this.spinnerService.state$;
constructor(
private spinnerService: SpinnerService,
private httpClient: HttpClient
) {}
ngOnInit() {}
}
HTML:
<p>List of Posts</p>
<ng-container *ngIf="(state$ | async); else printResult">
<h1>Loading...</h1>
</ng-container>
<ng-template #printResult>
<ng-container *ngIf="posts$ | async as posts">
<p *ngFor="let post of posts">
{{ post.title }}
</p>
</ng-container>
</ng-template>
通过拦截器的解决方案有些粗粒度。在某些时候,您可能需要更细粒度的解决方案。例如。显示多个并行 requests/components 的加载指示器。 Nil's blog post中给出了另一种解决方案。
您的问题有很多解决方案。希望对你有帮助。