如何最佳导入rxjs中的Observable?

90

在我的 Angular 2 应用程序中,我有一个服务,它使用了 rxjs 库中的 Observable 类。

import { Observable } from 'rxjs';

目前我只是使用 Observable ,这样我可以使用 toPromise() 函数。

我在另一个 StackOverflow 问题中读到,以这种方式导入,还从 rxjs/Rx 导入将会从 rxjs 库中导入许多不必要的东西,这将增加页面加载时间和/或代码库。

我的问题是,有什么最好的方法可以导入 Observable,以便我可以使用 toPromise() 函数,而无需导入其他所有内容?


2
import {Observable} from 'rxjs/Observable'; 这句话会引入 Observable,但是如果你正在使用 promises,你不需要全部引入它...toPromise 可以胜任。 - AT82
仅使用toPromise,我需要单独导入哪些内容?我正在使用Observable,我应该在问题中澄清这一点。实际上这是两个不同的问题。 - Danoram
2
如果你想使用promises,那么这个就可以了:import 'rxjs/add/operator/toPromise'; 请参考https://angular.io/docs/ts/latest/tutorial/toh-pt6.html 这应该会对你有所帮助 :) - AT82
我会调查一下。感谢你抽出时间分享! - Danoram
没问题!编码愉快! :) - AT82
显示剩余3条评论
3个回答

148

Rxjs v 6.*

新版本的rxjs更加简化。

1)操作符

import {map} from 'rxjs/operators';

2) 其他

import {Observable,of, from } from 'rxjs';

我们需要使用管道而不是链接。例如:

旧语法:

source.map().switchMap().subscribe()

新语法:

source.pipe(map(), switchMap()).subscribe()
注意: 由于与JavaScript保留字相同的名称冲突,一些操作符更名了!它们包括:

do -> tap,

catch -> catchError

switch -> switchAll

finally -> finalize


Rxjs v5.*

我撰写这篇答案部分原因是每次需要导入一个操作符时都要查看文档。如果有更好的方法,请告诉我。

1) import { Rx } from 'rxjs/Rx';

这将导入整个库。然后您无需担心加载每个操作符。但是需要附加Rx。我希望树摇能够优化并仅选择所需的函数(需要验证)如评论中所述,Tree-shaking无法帮助。因此,这不是最优化的方式。

public cache = new Rx.BehaviorSubject('');

或者您可以导入特定的运算符。

这将优化您的应用程序仅使用这些文件:

2)import { _______ } from 'rxjs/_________';

这种语法通常用于主对象,例如Rx本身或Observable等。

可以使用此语法导入的关键字:

 Observable, Observer, BehaviorSubject, Subject, ReplaySubject

3) import 'rxjs/add/observable/__________';

Angular 5更新说明

在使用rxjs 5.5.2+的Angular 5中,导入代码为:

import { empty } from 'rxjs/observable/empty';
import { concat} from 'rxjs/observable/concat';

通常这些会直接与 Observable 一起使用。例如:

Observable.from()
Observable.of()

可以使用此语法导入的其他关键字,包括:

concat, defer, empty, forkJoin, from, fromPromise, if, interval, merge, of, 
range, throw, timer, using, zip

4) import 'rxjs/add/operator/_________';

Angular 5 更新说明

在使用 rxjs 5.5.2+ 的 Angular 5 中,导入操作符的方式发生了变化。

import { filter } from 'rxjs/operators/filter';
import { map } from 'rxjs/operators/map';

这些通常在Observable创建后的流中出现。就像代码片段中的flatMap

Observable.of([1,2,3,4])
          .flatMap(arr => Observable.from(arr));

使用此语法的其他关键字:

audit, buffer, catch, combineAll, combineLatest, concat, count, debounce, delay, 
distinct, do, every, expand, filter, finally, find , first, groupBy,
ignoreElements, isEmpty, last, let, map, max, merge, mergeMap, min, pluck, 
publish, race, reduce, repeat, scan, skip, startWith, switch, switchMap, take, 
takeUntil, throttle, timeout, toArray, toPromise, withLatestFrom, zip

FlatMap: flatMapmergeMap的别名,因此我们需要导入mergeMap才能使用flatMap


/add导入注意事项:

在整个项目中我们只需要导入一次。因此建议在一个地方完成。如果它们被包含在多个文件中,并且其中一个文件被删除,构建将因错误原因而失败。


3
由于 RxJS 运算符模块不导出任何内容,而是改变全局状态,因此 Tree-shaking 在这里无法进行优化,因为它依赖于导出和导入定义的符号名称。请参考链接:https://christianliebel.com/2017/07/import-rxjs-correctly/。 - Mr. Smith
我认为你需要逐个导入运算符,例如 import { map } from 'rxjs/operators/map';import { filter } from 'rxjs/operators/filter'。 - Michael Burger
groupBy 在 Angular 5+ 上对我无效,但其他方法可以。 - Joe
很棒的答案。我不知道/add/operator/operators导入之间的区别。非常好用。 - Stephen Chung
这已经不再是事实,rxjs 6 的导入现在直接在 'rxjs' 或 'rxjs/operators'(或其他子模块)上进行。 - Enn
1
很酷,但在文档中哪里可以找到?我觉得 Rxjs 的文档很难使用。 - Robert Kusznier

22

RxJS 6更新(2018年4月)

现在可以直接从rxjs导入(如在Angular 6+中所示)。从rxjs/operators导入也是可以的,而且已经不再可能全局导入操作符(这是重构rxjs 6和使用pipe的新方法的主要原因之一)。感谢这个变化,现在可以使用treeshaking。

来自rxjs repo的示例代码:

import { Observable, Subject, ReplaySubject, from, of, range } from 'rxjs';
import { map, filter, switchMap } from 'rxjs/operators';

range(1, 200)
  .pipe(filter(x => x % 2 === 1), map(x => x + x))
  .subscribe(x => console.log(x));

rxjs < 6 的向后兼容性?

rxjs团队在npm上发布了一个兼容性包, 它几乎是安装和使用的。有了它,您的rxjs 5.x代码应该可以无问题运行。现在大多数依赖项(例如Angular模块)尚未更新,这一点尤其有用。


我在Angular 6.0.0-rc.5中遇到了问题。当时我不知道是RxJS做出了更改。我还从管道中删除了筛选器。 - Mikael S
RxJS6 有很多变化。强烈建议花时间阅读以下内容 https://github.com/ReactiveX/rxjs/blob/master/MIGRATION.md 和/或 https://auth0.com/blog/whats-new-in-rxjs-6/,以便为 RxJs7 做好准备,因为在那里会真正消失一些东西。正如 @enn 所提到的,现在应该使用 pipe 而不是将方法链接在一起。 - Simon_Weaver
这篇文章很好地解释了pipe的好处 https://gofore.com/en/lettable-operators-and-rxjs-versioning/ (虽然它不是专门讲RxJS6版本的,但它帮助我理解为什么RxJS6有这么多剧烈的变化,而官方指南并没有很好地解释)。 - Simon_Weaver

3

我从一些艰难的经历中学到的一件事是保持一致。

注意不要混淆以下内容:

 import { BehaviorSubject } from "rxjs";

使用

 import { BehaviorSubject } from "rxjs/BehaviorSubject";

这种方法在你尝试将对象传递给另一个类(以前是用另一种方式)时可能会出现问题,导致失败。

 (myBehaviorSubject instanceof Observable)

它失败了,因为原型链不同,结果为false。

我不能完全理解发生了什么,但有时我遇到这种情况需要改用更长的格式。


如果有人能更好地解释这个,请回复 :-) - Simon_Weaver
例如,Visual Studio可以轻松地从“rxjs”导入并合并定义,但在“长”格式中分别处理它们可能更好。 - Simon_Weaver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接