跟踪RxJ中的异步操作

时间:2016-11-29 15:36:54

标签: rxjs rxjs5

我订阅了异步step-api调用。当api调用正在进行时,我想显示加载动画。通过访问UI创建流时,它可以很容易done

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时(例如代码重用),跟踪异步操作的能力就会丢失,我无法显示加载动画。

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

提前致谢。

3 个答案:

答案 0 :(得分:2)

为什么不创建包含多个“事件”的流 - 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));

答案 1 :(得分:1)

您可以将额外的通知对象传递给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$可观察的。

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

你的装载机创建将是:

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

顺便说一句,因为你很好地使用rxjs,为什么不将它用于show / hide - angular2方式 - 并放弃jquery:

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

答案 2 :(得分:0)

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

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(...);
  }
}