RXJS:从分页界面创建可观察流的惯用方法

时间:2015-04-01 02:25:32

标签: reactive-programming rxjs

我有分页界面。给定起点,请求将生成结果列表和延续指示符。

我创建了一个observable,它是通过构造和平面映射一个读取页面的observable来构建的。此可观察对象的结果包含页面数据和要继续的值。我将数据和平面映射到订阅者。产生价值流。

为了处理分页,我为下一页的值创建了一个主题。它以初始值播种,然后每当我收到有效下一页的响应时,我会推送到页面主题并触发另一次读取,直到没有更多内容读取为止。

有没有更惯用的方法呢?

function records(start = 'LATEST', limit = 1000) {
  let pages = new rx.Subject();

  this.connect(start)
    .subscribe(page => pages.onNext(page));

  let records = pages
    .flatMap(page => {
      return this.read(page, limit)
        .doOnNext(result => {
          let next = result.next;
          if (next === undefined) {
            pages.onCompleted();
          } else {
            pages.onNext(next);
          }
        });
    })
    .pluck('data')
    .flatMap(data => data);

  return records;
}

1 个答案:

答案 0 :(得分:3)

这是一种合理的方式。它有几个潜在的缺陷(根据您的使用情况,可能会或可能不会影响您):

  1. 您无法观察this.connect(start)
  2. 中发生的任何错误
  3. 您的观察结果实际上是。如果调用者没有立即订阅observable(也许他们存储它并稍后订阅),那么他们将错过this.connect(start)的完成,并且observable似乎永远不会产生任何东西。
  4. 如果来电者改变主意并提前取消订阅,则无法取消订阅初始connect来电。这不是一个真正的大问题,但通常当构建一个可观察的时候,人们应该尝试将一次性用品链接在一起,这样如果调用者取消订阅,它就可以正常清理。
  5. 以下是修改后的版本:

    1. 它将错误从this.connect传递给观察者。
    2. 使用Observable.create创建一个 cold observable,只有当调用者实际订阅时才启动,因此没有机会错过初始页面值并停止流。
    3. 它将this.connect订阅一次性订阅与整体订阅一次性
    4. 相结合

      代码:

      function records(start = 'LATEST', limit = 1000) {
          return Rx.Observable.create(observer => {
              let pages = new Rx.Subject();
              let connectSub = new Rx.SingleAssignmentDisposable();
              let resultsSub = new Rx.SingleAssignmentDisposable();
              let sub = new Rx.CompositeDisposable(connectSub, resultsSub);
      
              // Make sure we subscribe to pages before we issue this.connect()
              // just in case this.connect() finishes synchronously (possible if it caches values or something?)
              let results = pages
                  .flatMap(page => this.read(page, limit))
                  .doOnNext(r => this.next !== undefined ? pages.onNext(this.next) : pages.onCompleted())
                  .flatMap(r => r.data);
              resultsSub.setDisposable(results.subscribe(observer));
      
              // now query the first page
              connectSub.setDisposable(this.connect(start)
                  .subscribe(p => pages.onNext(p), e => observer.onError(e)));
      
              return sub;
          });
      }
      

      注意:我之前没有使用过ES6语法,所以希望我没有弄乱任何东西。