什么是rxJS中的管道

时间:2018-02-07 16:28:01

标签: angular rxjs rxjs5

我认为我有基本概念,但有一些晦涩

所以一般来说这就是我使用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. 如果没有差异,为什么功能管存在?
  3. 为什么这些功能需要不同的进口?

4 个答案:

答案 0 :(得分:50)

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

我强烈建议您阅读官方文档https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md

主要区别在于,如果两个不同方想要创建同名的运算符,那么更容易制作自定义运算符并且更好地树可更改而不会更改某些可能发生冲突的全局const path = require('path'); const webpack = require('webpack'); let inputFolderPath = "js\\"; let outputFolderPath = "dist\\"; let bundleName = "bundle.js"; module.exports = { module: { rules: [ { test: /\.js$/, exclude: [/node_modules/], use: [{ loader: 'babel-loader' }], } ], }, plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ], externals: { myScoreUILib: 'MyScoreUILib' }, context: path.resolve(__dirname, inputFolderPath), entry: { app: './app.js', lib: './lib.bundle' }, output: { path: path.resolve(__dirname, outputFolderPath), filename: bundleName, }, devtool: 'source-map' }; 对象。 / p>

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

答案 1 :(得分:10)

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

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(函数( 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

答案 2 :(得分:6)

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

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

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

  

修补修补程序的点链问题是:

     

任何导入补丁程序运算符的库都会增加   该库的所有使用者的Observable.prototype,造成盲目   依赖性。如果库删除了它们的用法,他们将在不知不觉中   打破别人。使用管道时,您必须导入运算符   您需要将每个文件都放入其中。

     

直接修补到原型上的运算符不是“可摇树的”   通过汇总或webpack之类的工具。管道运算符将与他们一样   只是直接从模块引入的功能。

     

无法检测到正在应用程序中导入的未使用的运算符   可靠地通过任何形式的构建工具或棉绒规则。那意味着   您可能会导入扫描,但停止使用它,并且仍在添加   到您的输出包。使用管道运算符,如果您不使用   它,一个皮棉规则可以为您捡起它。

     

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

答案 3 :(得分:0)

管道方法

所有这些看起来很酷,但仍然很冗长。好吧,感谢RxJS 5.5,可观察对象现在在实例上提供了管道方法,使您可以使用我们所有的纯函数运算符调用管道来清理上面的代码:

  

那是什么意思?

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

const { Observable } = require('rxjs/Rx')
const { filter, map, reduce,  } = require('rxjs/operators')
const { pipe } = require('rxjs/Rx')

const filterOutEvens = filter(x => x % 2)
const doubleBy = x => map(value => value * x);
const sum = reduce((acc, next) => acc + next, 0);
const source$ = Observable.range(0, 10)

source$.pipe(
  filterOutEvens, 
  doubleBy(2), 
  sum)
  .subscribe(console.log); // 50