rxJS中的管道是什么


103

我想我有基本概念,但是有些模糊之处

因此,通常这就是我使用可观察的方式:

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. 如果没有区别,为什么功能管道存在?
  3. 为什么这些功能需要不同的导入?

1
我要说的是,它用于自定义非本地运算符,但是我什至不知道这是否正确。是否pipe()可以通过您创建的运算符?
zero298 '18

Answers:


69

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

我强烈建议您阅读官方文档https://rxjs.dev/guide/v6/pipeable-operators

主要的区别是,使自定义运算符更容易,并且具有更好的树状可操作性,同时又不更改某些全局Observable对象,如果两个不同的方面想要创建同名的运算符,则可能会导致冲突。

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


1
关于您的确认unused imports are ignored automatically,当前IDE具有可删除未使用导入的插件。
silvanasono

并非每个人都在使用这些IDE或这些插件,许多人使用基本的文本编辑器。大概在大多数时候,我们无法继续声明团队中的每个人都使用与我们相同的IDE /插件集/文本编辑器。
亚当·法里纳

3
@AdamFaryna当然,有些团队也可能在纸上写代码,但是如果他们拥有现代工具,他们为什么会这样做?使用文本编辑器(尤其是没有重要的插件)类似于在纸上编写代码。您可以这样做,但是为什么任何体面的团队/开发人员都可以这样做
Denes Papp

@DenesPapp代码编辑器无关紧要,因为人们可以以高效的方式使用它。除此之外,这只是个人喜好。您在纸上编写代码的类比是不准确的,无法在纸上执行代码,但是可以执行在任何文本编辑器中编写的代码。
亚当·法里纳

1
@perymimon您可以,但必须安装rxjs-compat软件包github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/…–
马丁

16

管道法

根据原始文件

pipable运算符是该函数将observables作为输入,并返回另一个observable。先前的observable保持不变。

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

原始帖子

管道是什么意思?

这意味着您先前在observable实例上使用的任何运算符都可以作为的纯函数使用rxjs/operators。这使得构建操作员组合或重用操作员变得非常容易,而无需诉诸各种编程体操,在这些体操中,您必须创建自定义可观察的扩展Observable,然后覆盖提升以创建自己的自定义内容。

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更改代码并给定属性.sorry,给您带来不便。
Chanaka Weerasinghe

谢谢,我什至没有意识到我可以将可管道运算符存储为函数引用,并在pipe()调用中使用它们。这比一直内联执行要干净得多。
亚历克斯。一个

9

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

它将流操作(映射,过滤,缩小...)与核心功能(订阅,管道)分离。通过管道操作而不是链接,它不会污染Observable的原型,从而使摇树变得更加容易。

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

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

导入修补程序运算符的任何库都将为该库的所有使用者扩展Observable.prototype,从而创建盲目依赖。如果库删除了它们的用法,它们将在不知不觉中破坏其他所有人。使用pipeable,必须将所需的运算符导入使用它们的每个文件中。

直接汇总到原型的操作员无法通过汇总或Webpack之类的工具“摇晃树”。可管道运算符将像直接从模块中引入的函数一样。

应用程序中导入的未使用的运算符无法通过任何类型的构建工具或lint规则可靠地检测到。这意味着您可以导入扫描,但是停止使用它,并且它仍被添加到输出包中。使用管道运算符,如果您不使用它,则可以使用皮棉规则为您选择它。

功能组成很棒。建立您自己的自定义运算符变得非常容易,现在它们可以正常工作,就像rxjs中的所有其他运算符一样。您无需再扩展Observable或覆盖提升。


8

有什么不同? 如您在示例中所见,主要区别在于提高了源代码的可读性。您的示例中只有两个函数,但是想像一下是否有十二个函数?然后它会像

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

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

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

这大大提高了可读性。

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

第一个函数采用可观察的值,对其进行处理,修改其值,然后传递给下一个函数,然后下一个函数采用第一个函数的可观察的输出,对其进行处理,然后传递给下一个函数,然后继续进行直到所有功能在pipe()函数内部使用该可观察的对象,最后您具有已处理的可观察的对象。最后,您可以使用subscribe()函数执行observable以从中提取值。请记住,原始可观察值未更改。 

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

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

  • 有从各个模块导入的可观察的管道地图类。 
  • 在该类的主体中,我使用了如代码所示的Pipe()函数。 
  • Of()函数返回一个可观察的对象,该对象在订阅时会顺序发射数字。

  • Observable尚未订阅。

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

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

  • 然后将处理后的Observable交给下一个函数(如果有),

  • 直到所有功能处理完Observable为止,

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

现在,Observable中的事情是,只要观察者没有订阅它,它就不会发出任何值。因此,我使用了subscription()函数来订阅此Observable,然后就订阅了它。of()函数开始发出值,然后通过pipe()函数对其进行处理,最后得到最终结果,例如,从of()函数中获取1,在map()函数中添加1,然后回来。您可以在subscribe(function(arguments){})函数内部将其作为参数获取。

如果要打印,则用作

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.