【问题标题】:RxJS filter() unexpected behaviourRxJS filter() 意外行为
【发布时间】:2019-11-03 03:57:30
【问题描述】:

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

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

以上代码在控制台输出hello

我所期望的是,既然过滤器只会允许成功的条件沿着算子链走下去,它怎么能通过 startWith() 输出 hello 呢?这是预期的行为吗?

【问题讨论】:

    标签: javascript functional-programming rxjs


    【解决方案1】:

    startWith 发生在您过滤了您的内容之后。

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

    因此,包含1 的流经过过滤以不让任何东西通过它本身就是一个东西。然后用startWith 操作符“修饰”那个东西,这使它产生一个初始的hello

    那个新的流就是你订阅的流!

    这确实是预期的行为。

    startWithpipe(...) 参数中高于filter,你会看到它是如何变化的:

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

    要解决 cmets 部分中的问题,您可以将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));
    

    很明显,过滤器不会影响更下游的操作员!

    【讨论】:

    • 但是过滤器不应该跳过后面的运算符链,所以 startWith 和它下面的所有都应该跳过?
    • filter 不会忽略操作符,它会过滤可观察流中的值。 startWith 使用传递给startWith的值预先添加(过滤值的)流
    • @emkay 我改进了我的答案。如果仍有问题困扰您,请随时告诉我!
    • @ccjmne 您对嵌套调用的解释很清楚。我真的忘记了,管道操作员只是在进行嵌套调用。
    【解决方案2】:

    startWith() 运算符只调用 concat() 运算符。将 start 参数作为第一个 observable,将外部 observable 作为第二个。

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

    concat() 运算符按从 leftright 的顺序发出每个 observable 的值。 first observable 必须发出所有值并在发出 next observable 之前完成。

    例如;

       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()重新排序 observables 的序列,以便首先发出 value,但由于它是一个运算符,它只能 lift 外部可观察的。放在pipe() 之后 startWith() 中的任何运算符都将应用于调用concat() 的结果的observable。

    【讨论】:

      猜你喜欢
      • 2019-09-01
      • 1970-01-01
      • 2019-05-16
      • 1970-01-01
      • 2017-01-02
      • 2017-04-28
      • 1970-01-01
      • 2017-03-10
      • 2019-05-01
      相关资源
      最近更新 更多