关于angular4中loading菊花图的触发机制及消失原理

Heptagon
  • 221

关于loading的出现及消失条件,当前的找到的解决方法是当发送的请求数与success的请求数成2倍关系时,认为所有的请求都结束了, 下图是从别的大触的git库里找到对Http重构的代码

 request(url: string | Request, options ?: RequestOptionsArgs): Observable<Response> {
        // 每多一个请求加一个定时器
        this.timer.push(setTimeout(() => {
            this.loading.open();
        }, 600));
        console.log('request,', url);
        this.count++;
        return this.intercept(super.request(url, options));
    }

    get(url: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.get(url, options));
    }

    post(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
    }

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
    }

    delete(url: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.delete(url, this.getRequestOptionArgs(options)));
    }

    patch(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.patch(url, body, this.getRequestOptionArgs(options)));
    }

    getRequestOptionArgs(options ?: RequestOptionsArgs): RequestOptionsArgs {
        return options;
    }

    // 拦截器
    intercept(observable: Observable<Response>): Observable<Response> {
        console.log('请求前', observable);
        return Observable.create((observer) => {
            observable.subscribe(res => {
                console.log('success:', res.json());
                observer.next(res);
            }, (err) => {
                console.log(123123123);
                observer.error(err);
                this.sum++;
                console.log('sum:', this.sum);
                console.log('count:', this.count);
                if (this.sum === this.count * 2) {
                    this.timer.forEach((c, i) => {
                        clearTimeout(this.timer[i]);
                    });
                    this.loading.close();
                }
            }, () => {
                // 每完成一个请求sum+1,直到所有的请求完成后才清除loading-bar定时器并关闭
                this.sum++;
                console.log('sum:', this.sum);
                console.log('count:', this.count);
                if (this.sum === this.count * 2) {
                    this.timer.forEach((c, i) => {
                        clearTimeout(this.timer[i]);
                    });
                    this.loading.close();
                }
                console.log('complete');
                observer.complete(); // 注意添加这句,否则有可能一些第三方的包不能正常使用,如ng2-translate
            });
        });
    }

但是因为在项目早期并没有按照这种严格的数量关系去写代码
比如声明了一个http请求,而并没有马上subscribe,只是存在了服务里,那就会导致count++而sum不变,因为重构旧的代码量着实有点大,所以想寻找一种新的方法。

比如是否可以通过rxjs,或者别的手段,抓取到正在pending的http列表,或者在app.component中实时的监控当前所有http流的返回值状态

回复
阅读 2.6k
2 个回答

之前给http拦截器加计数器的方法,本质上的矛盾在于实际当subsribe一个已经声明过的流时,由于没有调用http.get等方法,所以request与sum的数量关系被打破。所以对代码进行了优化

 timer: Array<any> = [];
    count = 0;
    sum = 0;

    constructor(backend: ConnectionBackend,
                defaultOptions: RequestOptions,
                public loading: LoadingBarService) {
        super(backend, defaultOptions);
    }

    // request(url: string | Request, options ?: RequestOptionsArgs): Observable<Response> {
    //     // this.loading.open();
    //     // 每多一个请求加一个定时器
    //     // this.timer.push(setTimeout(() => {
    //     //     console.log(123123);
    //     //     this.loading.open();
    //     //     // console.log(this.loading);
    //     // }, 600));
    //
    //     return this.intercept(super.request(url, options));
    // }

    get(url: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.get(url, options));
    }

    post(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
    }

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
    }

    delete(url: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.delete(url, this.getRequestOptionArgs(options)));
    }

    patch(url: string, body: string, options ?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.patch(url, body, this.getRequestOptionArgs(options)));
    }

    getRequestOptionArgs(options ?: RequestOptionsArgs): RequestOptionsArgs {
        return options;
    }

    // 拦截器
    intercept(observable: Observable<Response>): Observable<Response> {
        setTimeout(() => {
            this.loading.open();
        }, 1);

        return Observable.create((observer) => {
            this.count++;
            observable.subscribe(res => {
                observer.next(res);
            }, (err) => {
                observer.error(err);
                this.sum++;
                 if (this.sum === this.count) {
                   /.../
                }
              /..../
            }, () => {
                this.sum++;
                 if (this.sum === this.count) {
                    /.../
                }
                /.../
            });
        });
    }
}

优化的原理是,对实际被触发的observable进行监控(即Obeservable.create后的代码),比较流subscribe之前subscribe之后的sum和count的数量,这样就可以保证sum和count数量的对应关系
即sum === count时,所有http请求结束
具体清除timeout和其他代码按需添加即可

我觉得 angular 4.3.x 开始加入的 httpClient 是你想要的,加入了框架级的拦截器,只需要实现它就可以:

@Injectable()
export class MyHttpInterceptor implements HttpInterceptor {
    // ...
    public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // 在这里写请求发起之前的行为
        return next.handle(req).map((event) => {
            // 在这里写请求完成后的行为
            return event;
        });
    }
}

详细见官方文档

望有帮助

宣传栏