RxJs 6于2018年4月24日正式发布,为开发人员带来了一些使人兴奋的增补和改进。Ben Lesh, rxJS核心开发成员,强调:javascript
RxJs 6这些新的改动为开发人员提供了如下三方面的优化:模块化方面的改进、性能提高、调试更方便。RxJs团队尽力保持新版本的向后兼容性,可是为了减小RxJs的API数量,仍是引入了一些重大修改。java
下面让咱们一块儿来看一下RxJs团队在新版本中引入了哪些修改。git
为了便捷地从RxJS 5迁移到RxJS 6,RxJS团队发布了一个名为rxjs-compa
t的兄弟软件包。该软件包在v6
和v5
的API之间建立了一个兼容层。
RxJs团队建议开发人员经过安装^6.0.0
版本的rxjs
和rxjs-compat
包来升级现有应用:github
npm install rxjs@6 rxjs-compat@6 --save
此包容许您在升级RxJS 6的同时继续运行现有代码库,而不会出现问题。他支持在RxJs 6中移除掉的功能。
安装rxjs-compat
会致使打包后代码包体积的增长,若是你使用的是4.0.0版本如下的Webpack,该影响会被放大。
所以建议升级完成后将rxjs-compat
移除。web
只有两个重大修改在rxjs-compat
中未覆盖:ajax
在极少数状况下,您的代码库定义了它本身的TypeScript原型操做符并修改了Observable
命名空间。该状况下,您须要更新你的操做符相关代码才能使TypeScript正常编译。npm
在版本发布说明中,用户自定义的原型操做符可按以下方式建立:bash
Observable.prototype.userDefined = () => { return new Observable((subscriber) => { this.subscribe({ next(value) { subscriber.next(value); }, error(err) { subscriber.error(err); }, complete() { subscriber.complete(); }, }); }); }); source$.userDefined().subscribe();
为编译该类型的自定义操做符,须要作以下修改:websocket
const userDefined = <T>() => (source: Observable<T>) => new Observable<T>((subscriber) => { this.subscribe({ next(value) { subscriber.next(value); }, error(err) { subscriber.error(err); }, complete() { subscriber.complete(); }, }); }); }); source$.pipe( userDefined(), )
再也不支持在try / catch
块内调用Observable.subscribe()
。使用用Observable.subscribe()
方法中的错误回调方法替换原先的try / catch
块来完成的异步错误的处理。
示例以下:session
// deprecated try { source$.subscribe(nextFn, undefined, completeFn); } catch (err) { handleError(err); } // use instead source$.subscribe(nextFn, handleError, completeFn);
如今在Observable.subscribe()
中必须定义一个错误回调方法来异步处理错误。
如上所诉,rxjs-compat
提供了V5
与v6
API间的临时兼容层,实质上rxjs-compat
为您的代码库提供了所需的v5
版本功能,使得您能够逐步将您的代码库升级到v6版本。为了完成升级并移除rxjs-compat
依赖,您的代码库须要重构并中止使用v5
版本中的以下功能:
import
路径建议TypeScript开发人员使用rxjs-tslint
来重构import
路径。
RxJS团队设计了如下规则来帮助JavaScript开发人员重构import
路径:
rxjs
: 包含建立方法,类型,调度程序和工具库。
import { Observable, Subject, asapScheduler, pipe, of, from, interval, merge, fromEvent } from 'rxjs';
rxjs/operators
: 包含全部的管道操做符
import { map, filter, scan } from 'rxjs/operators';
rxjs/webSocket
: 包含websocket subject实现.
import { webSocket } from 'rxjs/webSocket';
rxjs/ajax
: 包含Rx ajax实现.
import { ajax } from 'rxjs/ajax';
rxjs/testing
: 包含RxJS的测试工具库.
import { TestScheduler } from 'rxjs/testing';
如下是一项小调查:您是否有常识使用rxjs-tslint
升级您的应用程序?
使用新的管道操做符语法替换旧有的链式操做。上一个操做符方法的结果会被传递到下一个操做符方法中。
不要移除rxjs-compat
包,直到你将全部的链式操做修改成管道操做符。若是您使用TypeScript, ts-lint
会在某种程度上自动执行此项重构。
Ben Lesh在ng-conf 2018上解释了为何咱们应该使用管道操做符。
请按照以下步骤将您的链式操做替换为管道操做:
从rxjs-operators
中引入您须要的操做符
注意:因为与Javascript保留字冲突,如下运算符名字作了修改:do
->tap
,catch
->
catchError
,switch
->switchAll
,finally
->finalize
import { map, filter, catchError, mergeMap } from 'rxjs/operators';
使用pipe()
包裹全部的操做符方法。确保全部操做符间的.
被移除,转而使用,
链接。记住!!!有些操做符的名称变了!!!
如下为升级示例:
// an operator chain source .map(x => x + x) .mergeMap(n => of(n + 1, n + 2) .filter(x => x % 1 == 0) .scan((acc, x) => acc + x, 0) ) .catch(err => of('error found')) .subscribe(printResult); // must be updated to a pipe flow source.pipe( map(x => x + x), mergeMap(n => of(n + 1, n + 2).pipe( filter(x => x % 1 == 0), scan((acc, x) => acc + x, 0), )), catchError(err => of('error found')), ).subscribe(printResult);
注意咱们在以上代码中嵌套使用了pipe()
。
使用函数而不是类来操做可观察对象(Observables)。全部的Observable类已被移除。他们的功能被新旧操做符及函数替代。这些替代品的功能与以前的类功能如出一辙。
示例以下:
// removed ArrayObservable.create(myArray) // use instead from(myArray) // you may also use new operator fromArray().
有关替换v5
类为v6
函数的完整列表,请查看RxJS文档。
ConnectableObservable
在v6中不能直接使用,要访问它,请使用操做符multicast
,publish
,publishReplay
和publishLast
。SubscribeOnObservable
在v6中不能直接使用,要访问它,请使用操做符subscribeOn
resultSelector
Result Selectors是一项没有被普遍使用甚至没有文档说明的RxJs特性,同时Result Selectors严重的增长了RxJs代码库的体积,所以RxJs团队决定弃用或删除他。
对于使用到该功能的开发人员,他们须要将esultSelector
参数替换为外部代码。
对于first()
, last()
这两个函数,这些参数已被移除,在删除rxjs-compat
以前务必升级代码。
对于其余拥有resultSelector
参数的函数,如mapping
操做符,该参数已被弃用,并
以其余方式重写。若是您移除rxjs-compat
,这些函数仍可正常工做,可是RxJs团队声明他们必须在v7版本发布以前将其移除。
针对该状况的更多详情,请查阅RxJs文档
Observable.if
and Observable.throw
Observable.if
已被iif()
取代,Observable.throw
已被throwError()
取代。您可以使用rxjs-tslint
将这些废弃的成员方法修改成函数调用。
代码示例以下:
// deprecated Observable.if(test, a$, b$); // use instead iif(test, a$, b$);
// deprecated Observable.throw(new Error()); //use instead throwError(new Error());
根据迁移指南,如下方法已被弃用或重构:
import { merge } from 'rxjs/operators'; a$.pipe(merge(b$, c$)); // becomes import { merge } from 'rxjs'; merge(a$, b$, c$);
import { concat } from 'rxjs/operators'; a$.pipe(concat(b$, c$)); // becomes import { concat } from 'rxjs'; concat(a$, b$, c$);
import { combineLatest } from 'rxjs/operators'; a$.pipe(combineLatest(b$, c$)); // becomes import { combineLatest } from 'rxjs'; combineLatest(a$, b$, c$);
import { race } from 'rxjs/operators'; a$.pipe(race(b$, c$)); // becomes import { race } from 'rxjs'; race(a$, b$, c$);
import { zip } from 'rxjs/operators'; a$.pipe(zip(b$, c$)); // becomes import { zip } from 'rxjs'; zip(a$, b$, c$);
RxJS 6带来了一些重大改变,可是经过添加rxjs-compat软件包能够缓解这一问题,该软件包容许您在保持v5代码运行的同时逐渐迁移。对于Typescript用户,其余中包括大多数Angular开发人员,tslint
提供了大量的自动重构功能,使转换变得更加简单。
任何升级与代码修改都会引入一些bug到代码库中。所以请务必测试您的功能以确保您的终端用户最终接受到相同的质量体验。