javascript - RxJs:通过 API 递归分页并从列表中查找值

标签 javascript rxjs operators expand pagination

我正在使用 rxjs v6.4.0。我正在尝试通过 API 进行分页,搜索名称等于“开发”的非常具体的 channel 。我正在使用 expand 递归调用 API 并获取新页面。最终结果为我提供了一个串联的 channel 列表。然后我过滤掉名称不等于“开发”的所有 channel 。但是我收到一个错误:TypeError:您在需要流的位置提供了“未定义”。您可以提供 Observable、Promise、Array 或 Iterable。

const Rx = require('rxjs')
const Rx2 = require('rxjs/operators')

const getChannel = (cursor) => {
  return this.service.getData(`${url}?cursor=${cursor || ''}`)
      .pipe(Rx2.map(resp => JSON.parse(resp.body)))
      .pipe(Rx2.expand(body => { // recurse the api until no more cursors
      return body.response_metadata && 
        body.response_metadata.next_cursor ? 
        getChannel(body.response_metadata.next_cursor) : Rx.EMPTY
    }))
    .pipe(Rx2.pluck('channels'))
    .pipe(Rx2.mergeAll()) // flattens array
    .pipe(Rx2.filter(c => {
      console.log('finding', c.name === 'development')
      return c.name === 'development'
    }))
}

最佳答案

find 回调应该返回一个 bool 值,而不是一个 Observable。例如

find(c => c.name === 'development')

更新

这是您的修改示例。我删除了生成器,因为它们比我们的案例需要的更复杂。

const { of, EMPTY, throwError } = rxjs;
const { filter, tap, expand, pluck, mergeAll } = rxjs.operators;

const DATA = 
  [ {channels: [{id: 123, name: 'test'}, {id:4, name: 'hello'}], cursor: 1}
  , {channels:[{id: 1, name: 'world'}, {id: 2, name: 'knows'}], cursor: 2}
  , {channels:[{id: 3, name: 'react'}, {id: 5, name: 'devcap'}], cursor: false}
  ];

function getChannel(){
  return getBlock()
    .pipe(
        expand(x => x.cursor ? getBlock(x.cursor) : EMPTY),
        pluck('channels'),
        mergeAll(),
        filter(c => c.name === 'devcap')
    )
}

getChannel().subscribe({
  next: console.log,
  error: console.error
});


function getBlock(index = 0) {
  if (index >= DATA.length){
    throwError('Out of bounds');
  }

  return of(DATA[index]);
}

更新 2

由于仅通过 getChannel() 完成递归,您的解决方案无效。当您执行 expand 时——您通过 getChannel() 运行另一个循环。这意味着您对每个递归获取的值运行 pluck-mergeAll-filter chain 两次!采摘和奉承它两次给你 undefined —— 因此错误。

在你的 playground 中——尝试分离出这段代码

let getValue = ()=>{
    const next = gen.next();
    if (!next || !next.value) { return EMPTY; }
    return next.value;
}

并在扩展中使用它,像这样:

let getChannel = () => {
   return getValue()
      .pipe(
        expand(body => {
          return body.cursor ? getValue() : EMPTY
        }),
        pluck('channels'),
        mergeAll(),
        filter(c => c.name === 'devcap'),
      )
}

关于javascript - RxJs:通过 API 递归分页并从列表中查找值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55274246/

相关文章:

javascript - Highcharts Columnrange数据标签高低不同颜色

c - 为什么将 sizeof 视为运算符?

javascript - 如何在 Redux 中使用级联更新对相互依赖的数据进行建模?

javascript - 为什么未定义的函数实际上是从 Javascript 闭包中调用的?

javascript - 使用来自不同窗口的变量

rxjs - 每个可观察值仅调用一次 RxJS 平面 map 函数

angular - 了解 Promise 与 Observables 的结果

angular - Angular 4 中的 Websocket 和 RxJS 混淆

javascript - jQuery/Javascript 比较运算符 "==="和 "=="

r - 如何提供(逻辑)运算符作为函数的参数