RxJS链式调用与可Lettable算子:拆分rxjs/add/*包对其未来的影响
rxjs/add/* 提案的影响 Great question—this is a common point of confusion for developers moving from RxJS's legacy prototype-based operators to the modern pipeable style, especially with the ongoing package restructuring discussions. Let's break down what this means for your code and future development:
1. 当前链式调用的状态
First off, you're right that the legacy prototype-based approach (using import 'rxjs/add/operator/map' to extend Observable's prototype) still works in current RxJS versions. However, this style has been officially deprecated since RxJS 5.5 in favor of pipeable operators. The codebase still supports it for backward compatibility, but it's no longer the recommended way to write RxJS code.
2. 拆分 rxjs/add/* 提案的直接影响
The proposal to split rxjs/add/* into separate packages is part of the team's push to phase out prototype extensions entirely. Here's what that would mean:
- No more built-in prototype extensions: You won't be able to import operators like
maporswitchMapfromrxjs/add/operator/within the core RxJS package anymore. - Separate package dependencies: To keep using the legacy chained style, you'd have to install individual packages for each operator you use (e.g.,
@rxjs/add-operator-map,@rxjs/add-operator-switchMap). This adds unnecessary overhead—managing dozens of tiny dependencies instead of a single RxJS package. - Gradual phase-out: It's likely that eventually, even these separate add-on packages will be discontinued, forcing a full migration to pipeable operators.
3. 为什么要放弃链式算子?
The core team has good reasons to move away from prototype extensions:
- Tree-shaking 效率更高:可 pipe 算子支持 tree-shaking。当你从
rxjs/operators导入map并在 pipe 中使用时,Webpack 这类打包工具可以把未使用的算子从最终包中剔除。而原型扩展只要导入就会修改全局Observable原型,哪怕没用的算子也会增加包体积。 - 无全局原型污染:扩展
Observable原型可能引发意外冲突,尤其是多个库以不同方式修改原型时。可 pipe 算子是纯函数,不会修改Observable类,完全避免了这个问题。 - TypeScript 支持更友好:可 pipe 算子的类型定义更清晰,TypeScript 能更准确地推断算子链中的类型。原型扩展有时会导致类型推断问题,尤其是复杂算子组合时。
4. 你应该怎么做?
既然你刚接触 RxJS 和 Angular,坚持使用可 pipe 算子风格(你提供的第二个代码示例)就对了。原因如下:
- 这是面向未来的写法——当
rxjs/add/*包被拆分或移除时,你不需要重写代码。 - 它符合 Angular 当前的最佳实践(NgRx 这类 Angular 生态库大量使用可 pipe 算子)。
- 灵活性更强:你可以轻松创建和组合自定义可 pipe 算子,这在原型扩展方式下没那么简单。
顺便给你的可 pipe 示例做个小修正:原来的 catch 算子在可 pipe 形式中是 catchError,而且应该放在 pipe() 调用内部,而不是链式调用。修正后的代码如下:
import { tap, takeUntil, map, switchMap, catchError } from 'rxjs/operators'; import { empty, of } from 'rxjs'; search$ = this._action .pipe( ofType<search.SearchCountry>(search.SEARCH_COUNTRY), map(action => action.payload), switchMap(query => { if (query === '') { return empty(); } const nextSearch$ = this._action.pipe( ofType(search.SEARCH_COUNTRY), skip(1) ); return this._searchService .search(query) .pipe( tap(query => console.log(query)), takeUntil(nextSearch$), map((result: RestResponseInterface) => new search.SearchCountryComplete(result)) ); }), catchError(error => { return of(new search.SearchError('Undocumented API Error')); }) );
内容的提问来源于stack exchange,提问作者Yousuf Jawwad

