【问题标题】:Tracking asynchronous operation in RxJs在 RxJs 中跟踪异步操作
【发布时间】:2016-11-29 15:36:53
【问题描述】:

我有一个具有异步步骤的订阅 - api 调用。在进行 api 调用时,我想显示加载动画。可以很容易地done 创建流并访问 UI:

Rx.Observable
    .combineLatest(page$, sorting$)
    .switchMap(function(args) {
        var page = args[0];
        var sorting = args[1];

        $('.overlay').show();

        return loadData(page, sorting);
    })
    .subscribe(function(data) {
        renderData(data);
        $('.overlay').hide();
    });

但是当我将流管理代码移动到 service(例如,为了代码重用)时,跟踪异步操作的能力会丢失,并且我无法显示加载动画。

有什么想法可以做到吗?从服务返回两个流?

提前致谢。

【问题讨论】:

    标签: rxjs rxjs5


    【解决方案1】:

    为什么不创建一个包含多个“事件”的流 - startedfinished,如下所示:

    function loadDataWithStartEvent($page, sorting$) {
      return Rx.Observable
        .combineLatest(page$, sorting$)
        .flatMap(args => {
          var page = args[0];
          var sorting = args[1];
    
          return Rx.Observable.just({ event : 'started' })
            .concat(
              // given that loadData returns an Observable<data> which only emits data one time
              loadData(pageSortingTuple.page, pageSortingTuple.sorting))
                .map(data => ({ event: 'finished', data: data}))
            );
        });    
    }
    

    现在您订阅如下:

    loadDataWithStartEvent(page$, sorting$)
      .doOnNext(evt => {
        if(evt.type == 'started') {
          $('overlay').show();
        } else {
          $('overlay').hide();
        }
      })
      .filter(evt => evt.type === 'finished')
      .map(evt => evt.data);
      .subscribe(data => renderData(data));
    

    【讨论】:

      【解决方案2】:

      您可以将额外的通知对象传递给setupLoading

      setupLoading: function(page$, sorting$, notify$) {
        return Rx.Observable
          .combineLatest(page$, sorting$)
          .switchMap(function(args) {
            notify$.next(true); // here we go...
            var page = args[0];
            var sorting = args[1];
      
            return loadData(page, sorting);
          });
      }
      

      然后创建,除了 page$sorting$loadStarted$ observable。

      loadStarted$.subscribe(() => $('.overlay').hide();
      

      您的加载器创建将是:

      service.setupLoading(page$, sorting$, loadStarted$)
        .subscribe(function(data) {
           renderData(data);
        });
      });
      

      顺便说一句,既然你很好地使用了 rxjs,为什么不将它用于显示/隐藏 - angular2 方式 - 并放弃 jquery:

      <div class="overlay" [style.display]="(showOverlay ? 'block' : 'none')>your overlay content here</div>
      

      【讨论】:

      • 附加流,我明白了。我希望有一些神奇的方法来避免它,但可能没有。
      • 为了简单起见,我使用了 jQuuery,在实际应用中我确实使用了 angular 2。
      【解决方案3】:

      最终我最终使用了自定义运算符:

      class RequestState {
        loading: boolean;
      }
      
      
      Observable.prototype.captureState = function captureState<T>(this: Observable<T>, state: RequestState): Observable<T> {
        state.loading = true;
      
        let onLoadingEnd = () => {
          state.loading = false;
        };
      
        obs = obs.do(onLoadingEnd, onLoadingEnd, onLoadingEnd);
      
        return obs;
      };
      
      
      class Component {
        requestState = new RequestState();
      
        ngOnInit() {
          this.api.endpoint(query)
            .captureState(this.requestState)
            .subscribe(...);
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-15
        • 2023-03-16
        • 1970-01-01
        • 2019-11-18
        相关资源
        最近更新 更多