链接过滤器函数时出现意外的索引值

Unexpected index values when chaining filter functions

下面的代码产生了我想要的结果:

// output 1,2,3,4,5,etc
var input$ = Rx.Observable.interval(500).map((v, idx) => idx+1);

var inputEveryOtherOdd$ = input$
  // filter even numbers
  .filter(v => v % 2)
  .map(x => x) // workaround to fix the index (read below)
  // filter every other remaining number (take every other odd number)
  .filter((v, idx) => {
    console.log(`Value: ${v}, Index: ${idx}`)
    return !(idx % 2);
  })
  .subscribe(function(v) {
    output.textContent+= v;
  })
;

日志产生:

Value: 1, Index: 0
Value: 3, Index: 1
Value: 5, Index: 2
Value: 7, Index: 3
Value: 9, Index: 4

通过第一个过滤器的每个项目都有下一个索引,因此每个项目的索引都会增加一个 (0,1,2,3,4,5,etc)

我无法理解的是,如果我删除 map,第二个过滤器会收到相同项目的不同 idx 值:

Value: 1, Index: 0
Value: 3, Index: 2
Value: 5, Index: 4
Value: 7, Index: 6
Value: 9, Index: 8

似乎在第一个过滤器中过滤的值仍在第二个过滤器中考虑。我无法理解它。过滤器函数不会 运行 用于值,那么索引如何为不存在的项目递增?为什么 map 有什么不同?

Click here for live demo.

我希望将两个过滤器链接在一起会产生与同步过滤相同的结果,并且每个过滤器中的 idx 值将是 0,1,2,3,4,5,etc

var result = [1,2,3,4,5,6,7,8,9]
  .filter(v => v % 2)
  .filter((v, idx) => !(idx % 2));

我最初使用 startWith 代替 map。似乎只是在过滤器之间放置一些东西就可以使 idx 值符合我的预期。

索引idx是元素在原始列表中的索引,与过滤掉的内容无关。

具有讽刺意味的是,这个问题是 RxJS 当前版本 (v4) 的 "feature"。

filter 运算符包含一项优化,用于检测它是否以 "chained" 方式使用,即是否连续有多个过滤器。如果是,那么它不会创建第二个 FilterObservable 而是将新的过滤器操作包装为现有 Observable 的一部分。

查看源代码here and here

因此,无论将多少过滤器链接在一起,您都总是收到所有过滤器的相同索引。

当您在两个过滤器之间使用运算符时,它无法执行优化,因此过滤器不会合并,您会看到不同的索引。