【问题标题】:What is pipe for in RxJS?RxJS 中的管道是什么?
【发布时间】:2018-07-18 00:46:23
【问题描述】:

我认为我有基本概念,但有些模糊

所以总的来说,这就是我使用 Observable 的方式:

observable.subscribe(x => {

})

如果我想过滤数据,我可以使用这个:

import { first, last, map, reduce, find, skipWhile } from 'rxjs/operators';
observable.pipe(
    map(x => {return x}),
    first()
    ).subscribe(x => {

})

我也可以这样做:

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';

observable.map(x => {return x}).first().subscribe(x => {

})

所以我的问题是:

  1. 有什么区别?
  2. 如果没有区别,为什么函数pipe存在?
  3. 为什么这些函数需要不同的导入?

【问题讨论】:

  • 我正要说它是针对自定义的、非本地的操作员的,但我什至不知道这是否正确。 pipe() 是否允许您传递您创建的运算符?

标签: angular rxjs rxjs5


【解决方案1】:

这就是我解释 observable 的方式:

您需要根据天气状况制定计划,以便打开收音机并收听 24/7 全天候广播天气状况的天气频道。在这种情况下,响应是持续进行的,而不是得到一个响应。这个响应就像订阅一个 observable。可观察的是“天气”,订阅是“让您保持最新状态的无线电信号”。只要您的收音机打开,您就会获得所有可用的更新。在您关闭收音机之前,您不会错过任何信息。

我说天气是可观察的,但你听的是收音机而不是天气。所以无线电也是一个可观察的。天气播音员所说的是气象学家发给他的天气报告的功能。气象学家所写的是来自气象站的数据的函数。来自气象站的数据是附属于它的所有仪器(气压计、风衰、风速计)的功能,而这些仪器是天气本身的功能。

在整个过程中至少有 5 个 observables。在这个过程中,有两种类型的 observables。源可观察和输出可观察。在此示例中,天气是“可观察的源”,而无线电是“可观察的输出”。介于两者之间的所有内容都代表PIPE FUNCTION

管道函数是对源 observable 执行操作以提供输出 observable 的功能,所有这些操作都发生在内部。这些操作都处理 observables 本身

【讨论】:

    【解决方案2】:

    “pipeable”(以前的“lettable”)运算符是自 RxJS 5.5 以来当前和推荐的使用运算符的方式

    我强烈推荐你阅读official documentation on pipeable operators

    主要区别在于,创建自定义运算符更容易,并且更易于 treeshak,同时不会更改一些全局 Observable 对象,如果两个不同的方想要创建同名的运算符,可能会发生冲突。

    为每个运算符 'rxjs/add/operator/first' 使用单独的 import 语句是制作更小的应用程序包的一种方法。通过只导入你需要的操作符而不是整个 RxJS 库,你可以显着减少总包的大小。但是编译器无法知道您是否导入了'rxjs/add/operator/first',因为您在代码中确实需要它,或者您只是在重构代码时忘记了删除它。这是使用管道运算符的优势之一,其中未使用的导入会被自动忽略。

    【讨论】:

    • 关于您的确认unused imports are ignored automatically,目前 IDE 有插件可以删除未使用的导入。
    • 不是每个人都在使用这些 IDE 或这些插件,很多人使用基本的文本编辑器。可能大多数时候,我们无法传达团队中的每个人都在使用与我们相同的 IDE/插件集/文本编辑器这一说法。
    • @AdamFaryna 当然,有些团队也可能在纸上编写代码,但如果他们有可用的现代工具,他们为什么要这样做呢?使用文本编辑器,尤其是没有重要插件的情况下,类似于在纸上编写代码。你可以这样做,但为什么任何体面的团队/开发人员会这样做
    • @DenesPapp 代码编辑器并不重要,只要人们可以高效地使用它。除此之外,这只是个人喜好。你对在纸上写代码的类比是不准确的,你不能在纸上执行代码,但是用任何文本编辑器编写的代码都可以执行。
    • @perymimon 你可以,但你必须安装rxjs-compatgithub.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/…
    【解决方案3】:

    有什么区别? 正如您在示例中看到的,主要区别在于提高源代码的可读性。您的示例中只有两个函数,但想象一下如果有十几个函数?然后它会像

    function1().function2().function3().function4()

    它真的变得丑陋且难以阅读,尤其是当您在函数内部填充时。除此之外,某些编辑器(如 Visual Studio 代码)不允许超过 140 行长度。但如果它像下面这样。

    Observable.pipe(
    function1(),
    function2(),
    function3(),
    function4()
    )
    

    这大大提高了可读性。

    如果没有区别,为什么存在函数管道? PIPE() 函数的目的是将所有接受并返回 observable 的函数汇总。它最初需要一个可观察对象,然后在其中使用的每个函数在整个 pipe() 函数中使用该可观察对象。

    第一个函数获取 observable,处理它,修改它的值,然后传递给下一个函数,然后下一个函数获取第一个函数的输出 observable,处理它,然后传递给下一个函数,然后继续直到pipe() 函数内部的所有函数都使用该 observable,最后你得到了处理后的 observable。最后,您可以使用 subscribe() 函数执行 observable 以从中提取值。请记住,原始 observable 中的值没有改变。!!

    为什么这些函数需要不同的导入? 导入取决于在 rxjs 包中指定函数的位置。 它是这样的。所有模块都存储在 Angular 的 node_modules 文件夹中。 从“模块”导入{类};

    我们以下面的代码为例。我刚刚在stackblitz中写了它。因此,不会自动生成任何内容,也不会从其他地方复制任何内容。当您也可以阅读时,我看不出复制 rxjs 文档中所述内容的意义。我假设您在这里问了这个问题,因为您不了解文档。

    • 有从 各自的模块。
    • 在类的主体中,我使用了 Pipe() 函数 如代码所示。
    • Of() 函数返回一个 observable,即 订阅时按顺序发出数字。

    • Observable 尚未订阅。

    • 当您像使用 Observable.pipe() 一样使用它时,pipe() 函数使用给定的 Observable 作为输入。

    • 第一个函数,map() 函数使用该 Observable,对其进行处理,将处理后的 Observable 返回给 pipe() 函数,

    • 那么处理过的 Observable 如果有的话就交给下一个函数,

    • 就这样继续下去,直到所有函数都处理完 Observable,

    • 最后,通过 pipe() 函数将 Observable 返回给变量,在以下示例中为 obs。

    现在 Observable 中的内容是,只要观察者没有订阅它,它就不会发出任何值。所以我使用 subscribe() 函数订阅了这个 Observable,然后我一订阅它。 of() 函数开始发射值,然后通过 pipe() 函数进行处理,最后得到最终结果,例如从 of() 函数中取出 1,在 map() 函数中加 1,并返回。您可以将该值作为 subscribe(function (argument) {}) 函数内部的参数获取。

    如果要打印,则用作

    subscribe( function (argument) {
        console.log(argument)
       } 
    )
    
        import { Component, OnInit } from '@angular/core';
        import { pipe } from 'rxjs';
        import { Observable, of } from 'rxjs';
        import { map } from 'rxjs/operators';
        
        @Component({
          selector: 'my-app',
          templateUrl: './app.component.html',
          styleUrls: [ './app.component.css' ]
        })
        export class AppComponent implements OnInit  {
        
          obs = of(1,2,3).pipe(
          map(x => x + 1),
          ); 
        
          constructor() { }
        
          ngOnInit(){  
            this.obs.subscribe(value => console.log(value))
          }
        }
    
    

    https://stackblitz.com/edit/angular-ivy-plifkg

    【讨论】:

    • 不知道。我更喜欢第一种方法。它对我来说看起来更干净,更合乎逻辑。
    • 第一种方法?
    • 我也一样。 fn().fn().fn() 看起来不错。管道有很多很好的理由,但我认为可读性并没有真正提高。我更喜欢的一个论点是,点表示法是针对对象属性和函数的,并且在这种情况下是人为的。从数学上讲,函数应该是 fn4(fn3(fn2(fn1()))) 现在 很丑。
    • 也可以说美在旁观者的眼中。
    • @DonDilanga pipable 操作符是将 observables 作为输入并返回另一个 observable 的函数。previous observable 保持不变。 - 这对管道操作员来说很重要。
    【解决方案4】:

    管道法

    According to original Documentation

    pipable 操作符是 函数将 observables 作为输入并返回另一个 observable .previous observable 保持不变。

    pipe(...fns: UnaryFunction<any, any>[]): UnaryFunction<any, any>
    

    Original Post

    管道是什么意思?

    这意味着您之前在 observable 在rxjs/operators 下可作为纯函数使用。 这使得构建运算符的组合或重用运算符 变得非常容易,无需求助于各种 编程体操,你必须创建一个自定义的 observable 扩展 Observable,然后覆盖 lift 只是为了制作您自己的自定义 东西。

    const { Observable } = require('rxjs/Rx')
    const { filter, map, reduce,  } = require('rxjs/operators')
    const { pipe } = require('rxjs/Rx')
    
    const filterOutWithEvens = filter(x => x % 2)
    const doubleByValue = x => map(value => value * x);
    const sumValue = reduce((acc, next) => acc + next, 0);
    const source$ = Observable.range(0, 10)
    
    source$.pipe(
      filterOutWithEvens, 
      doubleByValue(2), 
      sumValue)
      .subscribe(console.log); // 50
    

    【讨论】:

    • @VladKuts 更改代码和给定属性。抱歉给您带来不便。
    • 谢谢,我什至没有意识到我可以将支持管道的运算符存储为函数引用并在 pipe() 调用中使用它们。这比一直内联执行要干净得多。
    【解决方案5】:

    我想出的一个很好的总结是:

    它将流操作(map、filter、reduce...)与核心功能(订阅、管道)分离。通过管道操作而不是链接,它不会污染 Observable 的原型,从而更容易进行摇树。

    https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md#why

    用于点链的修补运算符的问题是:

    任何导入补丁操作符的库都会增加 该库的所有消费者的 Observable.prototype,创建盲目 依赖关系。如果图书馆取消了他们的使用,他们在不知不觉中 打破其他所有人。使用管道,您必须导入操作符 你需要进入你使用它们的每个文件。

    直接修补到原型上的操作员不是“可摇树”的 通过汇总或 webpack 等工具。可管道化的运营商将像他们一样 只是直接从模块中拉入的函数。

    无法检测到正在导入应用的未使用运算符 可靠地通过任何类型的构建工具或 lint 规则。这意味着 您可能会导入扫描,但停止使用它,它仍在添加中 到您的输出包。使用管道运算符,如果您不使用 它,一个 lint 规则可以为你挑选它。

    功能组合很棒。构建您自己的自定义运算符 变得非常非常容易,现在它们可以工作并且看起来就像所有 来自 rxjs 的其他运算符。您不需要扩展 Observable 或 不再覆盖提升。

    【讨论】:

      猜你喜欢
      • 2023-03-17
      • 2018-10-04
      • 2019-01-05
      • 1970-01-01
      • 2021-09-13
      • 2017-02-25
      • 2014-11-04
      • 2010-09-15
      • 2017-01-10
      相关资源
      最近更新 更多