RxJs:在flatMapLatest完成后访问flatMapLatest之前的数据

时间:2016-03-22 11:05:11

标签: javascript rxjs reactive-extensions-js

情景:

  1. 用户使用合并为单一流的过滤器
  2. 当过滤器更改时,会触发事件到后端以获取“便宜”数据
  3. 当“廉价”数据到达时,具有相同参数的另一个请求被触发到不同的端点,返回“昂贵”的数据,这些数据将用于丰富廉价数据。请求应延迟1秒,并且只有在用户不更改任何过滤器时才会被触发(否则它应该等待1秒)
  4. 我正在努力争取没有中间变量的选项。

    let filterStream = Rx.Observable
    .combineLatest(
      filterX,
      filterY,
      (filterX, filterY) => {
        x: filterX,
        y: filterY
      }
     )
     .map((filters) => {
      limit: 100,
      s: filters.x.a,
      f: filters.x.b + filters.y.c,
    })
    .distinctUntilChanged()
    
    
    let cheapDataStream = filterStream
    .flatMapLatest((filterQuery) =>
    Rx.Observable.fromPromise(cheapBackendApiCall(filterQuery)))
    
    // render cheap results
    cheapDataStream
    .map(result => transformForDisplay(result))
    .subscribe(result => { 
      //render
      // how do i invoke expensiveApiCall() with `filterQuery` data here?
      // with a delay, and only if filterQuery has not changed?
    
    });
    

3 个答案:

答案 0 :(得分:2)

您可以利用隐式转换来避免在任何地方明确使用fromPromise。然后你可以使用concat立即返回廉价数据,然后是延迟的昂贵+廉价数据。通过将其嵌套在flatMapLatest中,如果新查询到达,则流也将取消任何待处理的expensiveCalls

var filters = Rx.Observable
.combineLatest(
  filterX,
  filterY,
  (filterX, filterY) => {
    x: filterX,
    y: filterY
  }
 )
 .map((filters) => {
  limit: 100,
  s: filters.x.a,
  f: filters.x.b + filters.y.c,
})
.distinctUntilChanged()
.flatMapLatest(filters => {
  //This kicks off immediately
  var cheapPromise = cheapBackendApiCall(filters);

  //This was added in the latest version 4.1, the function is only called once it is subscribed to, 
  //if you are using earlier you will need to wrap it in a defer instead.
  var expensivePromiseFn = () => expensiveBackendApiCall(filters);

  //For join implicitly calls `fromPromise` so you can pass the same 
  // sort of arguments.
  var cheapAndExpensive = Rx.Observable.forkJoin(
                            cheapPromise, 
                            expensivePromiseFn, 
                            (cheap, expensive) => ({cheap, expensive}));

  //First return the cheap, then wait 1500 millis before subscribing 
  //which will trigger the expensive operation and join it with the result of the cheap one
  //The parent `flatMapLatest` guarantees that this cancels if a new event comes in
  return Rx.Observable.concat(cheap, cheapAndExpensive.delaySubscription(1500));
})
.subscribe(x => /*Render results*/);

答案 1 :(得分:0)

你在寻找debounce吗? 这个操作符似乎完全按照你的描述进行操作。

答案 2 :(得分:0)

我提出的解决方案,不确定是否()是合适的,并且廉价+昂贵的数据合并看起来不太反应。

Rx.Observable
.combineLatest(
  filterX,
  filterY,
  (filterX, filterY) => {
    x: filterX,
    y: filterY
  }
 )
 .map((filters) => {
  limit: 100,
  s: filters.x.a,
  f: filters.x.b + filters.y.c,
})
.distinctUntilChanged()
.flatMapLatest((filterQuery) =>
  Rx
  .Observable
  .fromPromise(cheapBackendApiCall(filterQuery))
  .map((results) => {
    filterQuery: filterQuery,
    results: results
  })
)
.do((filtersAndResults) => {
  // render filtersAndResults.results
})
.debounce(1500)
.flatMapLatest((filtersAndResults) => {
  return Rx
  .Observable
  .fromPromise(expensiveBackendApiCall(filtersAndResults.filterQuery))
  .map(results => {
    expensiveData: results,
    cheapData: filtersAndResults.results
  })
})
.subscribe((result)=> {
  // combine results.cheapData + results.expensiveData with simple .map and .find
  //  and render
})