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

时间:2015-11-19 21:14:35

标签: javascript reactive-programming rxjs

以下代码生成我想要的结果:

// 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)的索引都会加1。

我无法理解的是,如果我删除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值成为我所期望的值。

2 个答案:

答案 0 :(得分:1)

这个问题具有讽刺意味的是RxJS当前版本(v4)的“特征”。

filter运算符包含一个优化,以检测它是否以“链式”方式使用,也就是说,如果一行中有多个过滤器。如果是,那么它将不会创建第二个FilterObservable,而是将新的过滤操作包装为现有Observable的一部分。

请参阅源代码herehere

因此,无论您将多少个过滤器链接在一起,您始终将为所有过滤器接收相同的索引。

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

答案 1 :(得分:0)

索引{{1}}是原始列表中元素的索引,与已过滤的内容无关。