【问题标题】:How to show spinner only if data are fetched from Http service?仅当从 Http 服务获取数据时如何显示微调器?
【发布时间】:2019-03-25 13:45:23
【问题描述】:

我必须仅在 http 服务调用期间显示微调器,并在我的组件接收到数据时将其关闭。

我编写了一个小缓存服务,以便仅在第一次从 http 服务中获取数据,并在每次调用时从缓存中加载该数据,避免再次调用 http 服务。

服务按预期工作,但如果我只想在 http 调用期间而不是在从缓存中获取数据时显示微调器怎么办?

这是我的组件的代码,它在我的服务的 getReviewsCategory(this.id) 方法调用 http 服务时工作,但是当它从缓存中获取时,微调器永远不会被关闭。 数据在后台以正确的方式加载,但微调器继续运行。

presentLoading() 方法在 ngOnInit 中,所以每次都会调用它,如果我只想在从缓存中获取数据时调用它怎么办?我的组件怎么会知道它?


    ngOnInit() {
       this.presentLoading();
       this.CategoryCtrl();
     }

     CategoryCtrl() {
       this.serverService.getReviewsCategory(this.id)
       .subscribe((data) => {
         this.category_sources = data['value'];
         this.stopLoading();
       });
     }

     async presentLoading() {
       const loadingController = this.loadingController;

       const loadingElement = await loadingController.create({
         spinner: 'crescent',
       });
       return await loadingElement.present()
     }

     async stopLoading() {
       return await this.loadingController.dismiss();
     }

   }

EDIT1:这是 CacheService:


    import { Injectable } from '@angular/core';

    @Injectable({
      providedIn: 'root'
    })
    export class CachingService {

      constructor() { }

      private _cache = {};

      isCashed(url: string) {
        return this._cache[url];
      }

      getData(url: string) {
        return this._cache[url];
      }

      setData(url) {
        return (data) => {
          if (data && (data instanceof Error) === false) {
            this._cache[url] = data;
          };
        }
      }

      reset() {
        this._cache = {};
      }
    }

这是服务器服务的方法:



     getReviewsCategory(cat_id) : Observable<any> {
      if (this._c.isCashed(url)) {
            return of(this._c.getData(url));
          }else{
            var modeapp = window.sessionStorage.modeapp;
            var typemodeapp = typeof(window.sessionStorage.modeapp);
            if (modeapp === "online") {
              let promise = new Promise ((resolve, reject) => {
                this.httpNative.get(url, {}, {}).
                then((data) => {
                  let mydata = JSON.parse(data.data);
                  console.log("Data from HTTP: ");
                  console.log(mydata);
                  resolve(mydata);
                }, (error) => {
                  console.log("error in HTTP");
                  reject(error.error);
               }
              );
            });
              var observable = from(promise);
          }
        }
        return observable
        .pipe(
          tap(this._c.setData(url))
        );

【问题讨论】:

    标签: javascript angular typescript http ionic-framework


    【解决方案1】:

    我可以看到您正在从服务返回一个 observable,您可以尝试以下操作,看看这是否有帮助。

         CategoryCtrl() {
           this.serverService.getReviewsCategory(this.id)
           .subscribe((data) => {
             this.category_sources = data['value'];
             this.stopLoading();
           },
           (error) => console.log(error),
           () => this.stopLoading(); // This always execute
         );}
    

    文档:http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-subscribe

    但是,我相信问题可能来自您调用的对象.dismiss() 从。你应该在元素的实例而不是对象本身上调用dismiss。

    let loadingElement: Loading = null;
    
    async presentLoading() {
       const loadingController = this.loadingController;
       this.loadingElement = await loadingController.create({
         spinner: 'crescent',
       });
       return await loadingElement.present()
    }
    
    async stopLoading() {
       return await this.loadingElement.dismiss();
    }
    

    【讨论】:

    • 非常感谢...我不明白这一点,可观察的 this.serverService.getReviewsCategory(this.id) 发出一个值,无论该值来自http服务调用还是来自缓存,所以怎么可能我区分它们?
    • 如果两个返回值都是可观察的,您不必担心它们。这让我觉得问题可能出在操作顺序上。从缓存中获取这些值可能太快了,应用程序可能会在 presentLoading() 之前调用 stopLoading() 代码。您可以尝试几件事:在调用 create spinner 和/或从 presentLoading() 方法中删除所有那些 async/await 之前验证 this.category_sources 是否仍然为空。只在你期望 Promises 或者你知道是异步的代码中添加 async/await
    • 您可以检查数据的来源,但为此添加检查会添加更多代码并且无法解决问题。您的代码不应该关心数据是来自缓存还是数据库。此外,不能保证presentLoading()CategoryCtrl() 开始执行之前完成,因为它是一个异步 函数。保证这一点的唯一方法是await this.presentLoading(),或者,因为它返回一个承诺,所以做类似this.presentLoading().then(res =&gt; {this.CategoryCtrl();}的事情。
    • 我已经更新了上面的解决方案。我没有注意到这是 Ionic 框架中的常见构造,并认为它是常规的角度。
    • 伙计,我不知道该怎么感谢你!在 this.presentLoading() 上使用 .then 可以工作,微调器显示几毫秒然后关闭,而如果我使用 http 服务获取数据则需要更多时间。这不是我正在寻找的正确行为,因为我不想在缓存箱中显示所有微调器,但这肯定比我以前的要好得多!
    【解决方案2】:

    你可以使用HttpInterceptor类来拦截所有的http调用,并且在intercept方法中,你可以停止和启动一个spinner。

    从广义上讲,结构是:

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // Start the spinner.
        return next.handle(req).pipe(
            map((event: HttpEvent<any>) => {
                if (event instanceof HttpResponse) {
                    // Stop the spinner
                }
                return event;
            })
        );
    

    【讨论】:

      猜你喜欢
      • 2013-06-05
      • 2020-01-23
      • 2019-07-19
      • 1970-01-01
      • 2022-06-15
      • 1970-01-01
      • 1970-01-01
      • 2014-04-22
      • 1970-01-01
      相关资源
      最近更新 更多