RxJS 管道運算符

2020-10-09 15:31 更新

從5.5版開始,我們已經(jīng)發(fā)布了“可移植運算符”,可以在 進行訪問 rxjs/operators(請注意復數(shù)的“運算符”)中 。 與 找到的“ patch”運算符相比,這些方法是僅引入所需運算符的更好方法 rxjs-compat打包中 。

注意 :使用 rxjsrxjs/operators不更改構建過程可能會導致捆綁包增大。 請參閱 已知問題” 下面的“ 部分。

重命名運營商

由于使運算符獨立于 Observable 可用,因此運算符名稱不能與 JavaScript 關鍵字限制沖突。 因此,某些運算符的可移植版本的名稱已更改。 這些運算符是:

  1. do-> tap
  2. catch-> catchError
  3. switch-> switchAll
  4. finally-> finalize

let運算符現(xiàn)在是 一部分, Observableas 的 pipe無法導入。

  1. source$.let(myOperator) -> source$.pipe(myOperator)

請參閱下面的“ 建立自己的運營商 ”。

toPromise()“操作員”已被刪除 因為運算符返回 Observable, 不是一個 Promise。 現(xiàn)在有一個 Observable.toPromise()實例方法。

為什么?

修補的點鏈運算符的問題是:

  1. 導入修補程序運算符的任何庫 增加 Observable.prototype都將為該庫的所有使用者 ,從而造成盲目依賴。 如果庫刪除了它們的用法,它們將在不知不覺中破壞其他所有人。 使用 pipeable,必須將所需的運算符導入使用它們的每個文件中。

  1. 直接 到原型的操作員無法 “搖晃樹”匯總 通過匯總或 Webpack 之類的工具 。 可管道運算符將像直接從模塊中引入的函數(shù)一樣。

應用程序中導入的未使用的運算符無法通過任何類型的構建工具或 lint 規(guī)則可靠地檢測到。 這意味著您可以導入 scan,但停止使用它,并且仍將其添加到您的輸出包中。 對于可管道運算符,如果您不使用它,則可以使用皮棉規(guī)則為您選擇它。

功能組成很棒。 建立您自己的自定義運算符變得容易得多,現(xiàn)在它們可以正常工作,并且看起來就像 rxjs 中的所有其他運算符一樣。 您不需要擴展 Observable 或覆蓋它 lift。

什么?

什么是管道運算符? 簡而言之,可以與當前 一起使用的函數(shù) let運算符 。 它曾經(jīng)是名稱(“ lettable”)的起源,但是這令人困惑,因此我們現(xiàn)在將它們稱為“ pipeable”,因為它們打算與 一起使用 pipe實用程序 。 可管道運算符基本上是任何返回帶有簽名的函數(shù)的函數(shù): <T, R>(source: Observable<T>) => Observable<R>。

有一個 的 pipe內(nèi)置 方法 Observable現(xiàn)在, Observable.prototype.pipe可以用來像與點鏈接所用的相似方式組成運算符(如下所示)。

pipe可以從導入實用程序功能 import { pipe } from 'rxjs';。 該 pipe功能可用于從其他管道運算符構建可重用的管道運算符。 例如:

  1. import { pipe } from 'rxjs';
  2. import { map } from 'rxjs/operators';
  3. const mapTwice = <T,R>(fn: (value: T, index: number) => R) => pipe(map(fn), map(fn));

用法

您可以在 下從一個位置引入所需的任何運算符 'rxjs/operators'復數(shù)! ) 。 還建議直接使用所需的 Observable 創(chuàng)建方法,如下所示 range

  1. import { range } from 'rxjs';
  2. import { map, filter, scan } from 'rxjs/operators';
  3. const source$ = range(0, 10);
  4. source$.pipe(
  5. filter(x => x % 2 === 0),
  6. map(x => x + x),
  7. scan((acc, x) => acc + x, 0)
  8. )
  9. .subscribe(x => console.log(x))
  10. // Logs:
  11. // 0
  12. // 4
  13. // 12
  14. // 24
  15. // 40

輕松建立自己的運營商

實際上,您 始終 來 可以使用 做到這一點, let... 但是構建自己的運算符現(xiàn)在就像編寫函數(shù)一樣簡單。 注意,您可以將自定義運算符與其他 rxjs 運算符無縫組合在一起。

  1. import { Observable, interval } from 'rxjs';
  2. import { filter, map, take, toArray } from 'rxjs/operators';
  3. /**
  4. * an operator that takes every Nth value
  5. */
  6. const takeEveryNth = (n: number) => <T>(source: Observable<T>) =>
  7. new Observable<T>(observer => {
  8. let count = 0;
  9. return source.subscribe({
  10. next(x) {
  11. if (count++ % n === 0) observer.next(x);
  12. },
  13. error(err) { observer.error(err); },
  14. complete() { observer.complete(); }
  15. })
  16. });
  17. /**
  18. * You can also use an existing operator like so
  19. */
  20. const takeEveryNthSimple = (n: number) => <T>(source: Observable<T>) =>
  21. source.pipe(filter((value, index) => index % n === 0 ))
  22. /**
  23. * And since pipeable operators return functions, you can further simplify like so
  24. */
  25. const takeEveryNthSimplest = (n: number) => filter((value, index) => index % n === 0);
  26. interval(1000).pipe(
  27. takeEveryNth(2),
  28. map(x => x + x),
  29. takeEveryNthSimple(3),
  30. map(x => x * x),
  31. takeEveryNthSimplest(4),
  32. take(3),
  33. toArray()
  34. )
  35. .subscribe(x => console.log(x));
  36. // Logs:
  37. // [0, 2304, 9216]

已知的問題

打字稿<2.4

在 TypeScript 2.3及更低版本中,由于無法在 TypeScript 2.4之前推斷類型,因此需要將類型添加到傳遞給運算符的函數(shù)中。 在 TypeScript 2.4中,類型將通過合成正確推斷。

TS 2.3 and under

  1. range(0, 10).pipe(
  2. map((n: number) => n + '!'),
  3. map((s: string) => 'Hello, ' + s),
  4. ).subscribe(x => console.log(x))

TS 2.4 以上

  1. range(0, 10).pipe(
  2. map(n => n + '!'),
  3. map(s => 'Hello, ' + s),
  4. ).subscribe(x => console.log(x))

建造和搖樹

從清單文件(或重新導出)導入時,應用程序捆綁有時會增長。 現(xiàn)在可以從中導入可管道運算符 rxjs/operators,但是在不更改生成過程的情況下這樣做通常會導致應用程序包更大。 這是因為默認情況下 rxjs/operators將解析為 rxjs 的 CommonJS 輸出。

為了使用新的管道運算符而不增加捆綁包的大小,您將需要更改 Webpack 配置。 這僅適用于 Webpack 3+,因為它依賴于 的新 ModuleConcatenationPluginWebpack 3 中 功能。

路徑映射

與 rxjs 5.5 一起發(fā)布的是帶有 ES5 和 ES2015 語言級別的 ECMAScript 模塊格式(導入和導出)的 rxjs 構建。 您可以在 找到這些分布 node_modules/rxjs/_esm5和中 node_modules/rxjs/_esm2015(“ esm”代表 ECMAScript 模塊,數(shù)字“ 5”或“ 2015”代表 ES 語言級別)。 在應用程序源代碼中,應從導入 rxjs/operators,但在 Webpack 配置文件中,將需要將導入重新映射為 ESM5(或 ESM2015)版本。

如果是 require('rxjs/_esm5/path-mapping'),您將收到一個函數(shù),該函數(shù)返回鍵-值對的對象,將每個輸入映射到其在磁盤上的文件位置。 使用此映射,如下所示:

webpack.config.js

配置簡單:

  1. const rxPaths = require('rxjs/_esm5/path-mapping');
  2. const webpack = require('webpack');
  3. const path = require('path');
  4. module.exports = {
  5. entry: 'index.js',
  6. output: 'bundle.js',
  7. resolve: {
  8. // Use the "alias" key to resolve to an ESM distribution
  9. alias: rxPaths()
  10. },
  11. plugins: [
  12. new webpack.optimize.ModuleConcatenationPlugin()
  13. ]
  14. };

更完整的配置(更接近實際場景):

  1. const webpack = require('webpack');
  2. const path = require('path');
  3. const HtmlWebpackPlugin = require('html-webpack-plugin');
  4. const DashboardPlugin = require('webpack-dashboard/plugin');
  5. const nodeEnv = process.env.NODE_ENV || 'development';
  6. const isProd = nodeEnv === 'production';
  7. const rxPaths = require('rxjs/_esm5/path-mapping');
  8. var config = {
  9. devtool: isProd ? 'hidden-source-map' : 'cheap-eval-source-map',
  10. context: path.resolve('./src'),
  11. entry: {
  12. app: './index.ts',
  13. vendor: './vendor.ts'
  14. },
  15. output: {
  16. path: path.resolve('./dist'),
  17. filename: '[name].bundle.js',
  18. sourceMapFilename: '[name].map',
  19. devtoolModuleFilenameTemplate: function (info) {
  20. return "file:///" + info.absoluteResourcePath;
  21. }
  22. },
  23. module: {
  24. rules: [
  25. { enforce: 'pre', test: /\.ts$|\.tsx$/, exclude: ["node_modules"], loader: 'ts-loader' },
  26. { test: /\.html$/, loader: "html" },
  27. { test: /\.css$/, loaders: ['style', 'css'] }
  28. ]
  29. },
  30. resolve: {
  31. extensions: [".ts", ".js"],
  32. modules: [path.resolve('./src'), 'node_modules'],
  33. alias: rxPaths()
  34. },
  35. plugins: [
  36. new webpack.DefinePlugin({
  37. 'process.env': { // eslint-disable-line quote-props
  38. NODE_ENV: JSON.stringify(nodeEnv)
  39. }
  40. }),
  41. new webpack.HashedModuleIdsPlugin(),
  42. new webpack.optimize.ModuleConcatenationPlugin(),
  43. new HtmlWebpackPlugin({
  44. title: 'Typescript Webpack Starter',
  45. template: '!!ejs-loader!src/index.html'
  46. }),
  47. new webpack.optimize.CommonsChunkPlugin({
  48. name: 'vendor',
  49. minChunks: Infinity,
  50. filename: 'vendor.bundle.js'
  51. }),
  52. new webpack.optimize.UglifyJsPlugin({
  53. mangle: false,
  54. compress: { warnings: false, pure_getters: true, passes: 3, screw_ie8: true, sequences: false },
  55. output: { comments: false, beautify: true },
  56. sourceMap: false
  57. }),
  58. new DashboardPlugin(),
  59. new webpack.LoaderOptionsPlugin({
  60. options: {
  61. tslint: {
  62. emitErrors: true,
  63. failOnHint: true
  64. }
  65. }
  66. })
  67. ]
  68. };
  69. module.exports = config;
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號