合并的observable即使合并也不包含序列

时间:2016-08-30 15:15:56

标签: javascript rxjs reactivex

我有一个基本上采用DOM元素的函数,查找一些识别内容,并且(理论上)返回一个Observable,其中包含上述标识内容withLatestFrom和其他一些内容

我的问题是,返回的Observable不会发出任何问题,即使它是由primaries$highlights$可观察到的。{/ p>

如果解释得不好,我非常抱歉,我是ReactiveX / RxJS的新手,我正在尽我所能;如果您需要更多信息,请询问。

function randomFunction(element) {
  // Create an observable sequence of text nodes from an array
  const textNodes$ = Rx.Observable.from(getAllTextNodesFrom(element))

  // Get "highlights" by doing stuff with text nodes
  const highlights$ = textNodes$
    .map(doSomeStuff)
    .zip(textNodes$, (res, node) => ({res, node}))
    .filter(({res, node}) => res.length && node.isConnected)

  // Get "primaries" by doing stuff with "highlights"
  const primaries$ = highlights$
    .map(x => x.res)
    .flatMap(x => x.filter(y => y.matches && y.isPrimary))
    .map(x => x.id)
    .toSet()

  // Create return observable from highlights and primaries
  const ret$ = highlights$.withLatestFrom(primaries$)

  // These work
  primaries$.subscribe(x => { console.log("primaries:", x) })
  highlights$.subscribe(x => { console.log("highlights:", x) })

  // This gives me nothing
  ret$.subscribe(x => { console.log("return:", x) })

  return ret$
}

谢谢!

2 个答案:

答案 0 :(得分:1)

我观察到你使用了两次observable,在这种情况下你可能share这些常见的源可观察。例如,highlights$将订阅两次,一次为ret生成值,一次生成primaries的值。

除此之外,您还可以使用dotap运算符进行日志记录,这将在不影响流的情况下执行日志记录副作用。您确实需要一个subscribe来启动数据流。当您订阅ret时,它会订阅highlightprimaries并上订阅链。

最后一句话,Rxjs中的多个订阅都很棘手。你需要意识到热与冷的二分法才能理解会发生什么。您可以找到详细检查内部工作here

类似于:

function randomFunction(element) {
  // Create an observable sequence of text nodes from an array
  const textNodes$ = Rx.Observable.from(getAllTextNodesFrom(element))

  // Get "highlights" by doing stuff with text nodes
  const highlights$ = textNodes$
    .map(doSomeStuff)
    .zip(textNodes$, (res, node) => ({res, node}))
    .filter(({res, node}) => res.length && node.isConnected)
    .share()
    .tap(console.log.bind(console, 'highlights:'))

  // Get "primaries" by doing stuff with "highlights"
  const primaries$ = highlights$
    .map(x => x.res)
    .flatMap(x => x.filter(y => y.matches && y.isPrimary))
    .map(x => x.id)
    .toSet()
    .tap(console.log.bind(console, 'primaries:'))

  // Create return observable from highlights and primaries
  const ret$ = highlights$.withLatestFrom(primaries$)

  // These work
  ret$.subscribe(x => { console.log("return:", x) })

  return ret$
}

答案 1 :(得分:0)

Building on what user3743222 said in their answer, turns out I also needed to pause/buffer highlights$ when creating ret$, and wait for primaries$ to emit something before continuing. Here's how I did that using Rx.Observable.prototype.pausableBuffered

function randomFunction(element) {
  // Create an observable sequence of text nodes from an array
  const textNodes$ = Rx.Observable.from(getAllTextNodesFrom(element))

  // Get "highlights" by doing stuff with text nodes
  const highlights$ = textNodes$
    .map(doSomeStuff)
    .zip(textNodes$, (res, node) => ({res, node}))
    .filter(({res, node}) => res.length && node.isConnected)
    .share()
    .tap(console.log.bind(console, 'highlights:'))

  // Get "primaries" by doing stuff with "highlights"
  const primaries$ = highlights$
    .map(x => x.res)
    .flatMap(x => x.filter(y => y.matches && y.isPrimary))
    .map(x => x.id)
    .toSet()
    .tap(console.log.bind(console, 'primaries:'))

  // Observable that outputs true when primaries$ outputs anything
  const primariesExist$ = primaries$.map(() => true)

  // Create return observable from highlights and primaries
  return highlights$
    .pausableBuffered(primariesExist$)
    .withLatestFrom(primaries$)
}