RxJS filter()意外行为

时间:2019-06-20 10:34:23

标签: javascript functional-programming rxjs

我遇到了这种奇怪的行为或我不知道的事情。 对于以下内容,

of(1).pipe(
  filter(_ => false),
  startWith('hello')
).susbcribe(val => console.log(val));

以上代码在控制台中输出hello

我期望的是,由于filter仅允许成功的条件沿操作员链下降,因此它如何通过startWith()输出hello?这是预期的行为吗?

2 个答案:

答案 0 :(得分:2)

startWith在您过滤内容之后发生

of(1).pipe(           // will yield (1)
  filter(_ => false), // will yield ()
  startWith('hello')  // will yield ('hello')
).susbcribe(val => console.log(val));

因此,由1组成的流经过过滤以使任何内容都不通过本身就是一件事。然后用startWith运算符对该东西进行“修饰”,使其产生初始的hello

这是您订阅的新信息流!

这确实是预期的行为。

startWith参数中将filter置于pipe(...)上方,您将看到这种变化:

of(1).pipe(           // will yield (1)
  startWith('hello'), // will yield ('hello', 1)
  filter(_ => false)  // will yield ()
).susbcribe(val => console.log(val));

要解决评论部分中的问题,可以将pipe链视为nested calls。例如,使用伪代码:

A.pipe(B, C, D)

...等价于:

D(C(B(A)))

因此,以下内容:

of(1).pipe(           // expression A
  filter(_ => false), // expression B
  startWith('hello')  // expression C
).susbcribe(val => console.log(val));

...将翻译为:

startWith(         // expression C
    filter(        // expression B
        of(1),     // expression A
        _ => false
    ),
    'hello'
).susbcribe(val => console.log(val))

或者,以一种更“必要”的方式:

const one = of(1);
const filtered = filter(one, _ => false);
const greeted = startWith(filtered, 'hello');
greeted.subscribe(val => console.log(val));

然后很明显,过滤器不会不会影响到运营商的下游!

答案 1 :(得分:0)

startWith()运算符仅调用concat()运算符。起始参数为第一个可观察值,外部参数为第二个。

https://github.com/ReactiveX/rxjs/blob/40a2209636a8b4d4884f5d59ad206ae458ad2de4/src/internal/operators/startWith.ts#L68

concat()运算符为从 left right 的每个可观察值发出值。 first 可观察对象必须发出所有值,并在发出 next 可观察对象之前完成。

例如;

   concat(of('a','b'), of('1', '2')
      .subscribe(val => console.log(val));
   // prints 'a', 'b', '1', '2'

因此,我们可以重写示例以使用concat()并生成相同的结果,这基本上就是startWith()在内部所做的事情。

   concat(of('hello'), of(1).pipe(filter(_ => false))
      .subscribe(val => console.log(val));
   // prints "hello"

因此startWith() 对可观察对象的序列进行重新排序,以便首先发出,但是由于它是一个运算符,因此只能 lift < / em>外部可观察到的。在pipe()之后 startWith()中放置在concat() 之后的任何运算符都将应用于可观察对象。