Best way to import Observable from rxjs
Asked Answered
K

3

90

In my angular 2 app I have a service that uses the Observable class from the rxjs library.

import { Observable } from 'rxjs';

At the moment I am just using Observable so that I can use the toPromise() function.

I read in another StackOverflow question somewhere that importing in this way and also importing from rxjs/Rx will import a whole lot of unnecessary stuff from the rxjs library that will increase the page load times and/or the code base.

My question is, what is the best way to import Observable so I can use the toPromise() function without having to import everything else?

Kaffraria answered 21/2, 2017 at 20:7 Comment(8)
import {Observable} from 'rxjs/Observable'; would import the Observable, but you don't need to import it all if you are using promises... toPromise works without it.Galvanize
What would I need to import by itself to use just toPromise? I am using Observable, I should have clarified that in the question. it's really two separate questions.Kaffraria
then this would do, if you want promises import 'rxjs/add/operator/toPromise'; Take a look at angular.io/docs/ts/latest/tutorial/toh-pt6.html That should help you along :)Galvanize
I'll look into it. Cheers and thanks for taking the time to share!Kaffraria
No problem! Happy coding! :)Galvanize
This is no longer correct for rxjs 6+.Interconnect
Can you elaborate on which part is incorrect, for other visitors to this page.Kaffraria
Please see my answer below for more info.Interconnect
K
148

Rxjs v 6.*

It got simplified with newer version of rxjs .

1) Operators

import {map} from 'rxjs/operators';

2) Others

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

Instead of chaining we need to pipe . For example

Old syntax :

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

New Syntax:

source.pipe(map(), switchMap()).subscribe()

Note: Some operators have a name change due to name collisions with JavaScript reserved words! These include:

do -> tap,

catch -> catchError

switch -> switchAll

finally -> finalize


Rxjs v 5.*

I am writing this answer partly to help myself as I keep checking docs everytime I need to import an operator . Let me know if something can be done better way.

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

This imports the entire library. Then you don't need to worry about loading each operator . But you need to append Rx. I hope tree-shaking will optimize and pick only needed funcionts( need to verify ) As mentioned in comments , tree-shaking can not help. So this is not optimized way.

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

Or you can import individual operators .

This will Optimize your app to use only those files :

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

This syntax usually used for main Object like Rx itself or Observable etc.,

Keywords which can be imported with this syntax

 Observable, Observer, BehaviorSubject, Subject, ReplaySubject

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

Update for Angular 5

With Angular 5, which uses rxjs 5.5.2+

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

These are usually accompanied with Observable directly. For example

Observable.from()
Observable.of()

Other such keywords which can be imported using this syntax:

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

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

Update for Angular 5

With Angular 5, which uses rxjs 5.5.2+

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

These usually come in the stream after the Observable is created. Like flatMap in this code snippet:

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

Other such keywords using this syntax:

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: flatMap is alias to mergeMap so we need to import mergeMap to use flatMap.


Note for /add imports :

We only need to import once in whole project. So its advised to do it at a single place. If they are included in multiple files, and one of them is deleted, the build will fail for wrong reasons.

Kinelski answered 6/7, 2017 at 8:30 Comment(6)
Tree-shaking can't optimize here as it relies on the symbol names of export and import definitions and RxJS operator modules don’t export anything, but change global state instead. seeMellar
I think you have to import any operator one by one like import { map } from 'rxjs/operators/map }; import { filter } from 'rxjs/operators/filter }Ginny
groupBy didn't work for me on Angular 5+, others did though.Harangue
Great answer. I didn't know the difference between /add/operator vs /operators imports. Works like a charm.Indelible
This is no longer the case, rxjs 6 imports are now done directly on the 'rxjs' or 'rxjs/operators' (or other submodules)Interconnect
Cool, but where is that in the documentation? I find Rxjs documentation hard to use.Grisaille
I
22

Update for RxJS 6 (April 2018)

It is now perfectly fine to import directly from rxjs. (As can be seen in Angular 6+). Importing from rxjs/operators is also fine and it is actually no longer possible to import operators globally (one of major reasons for refactoring rxjs 6 and the new approach using pipe). Thanks to this treeshaking can now be used as well.

Sample code from 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));

Backwards compatibility for rxjs < 6?

rxjs team released a compatibility package on npm that is pretty much install & play. With this all your rxjs 5.x code should run without any issues. This is especially useful now when most of the dependencies (i.e. modules for Angular) are not yet updated.

Interconnect answered 5/4, 2018 at 5:57 Comment(3)
I had the problem in Angular 6.0.0-rc.5. And I didn't know that it was RxJS who had made the change. I also removed the filter from the pipe.Malliemallin
There are a lot of changes in RxJS6. Highly recommend taking the time to read this github.com/ReactiveX/rxjs/blob/master/MIGRATION.md and/or auth0.com/blog/whats-new-in-rxjs-6 so you can prepare for RxJs7 where things will really disappear. As @enn mentioned you now should be using pipe instead of chaining methods togetherSpurgeon
This article is great in explaining the benefits of pipe gofore.com/en/lettable-operators-and-rxjs-versioning (it is not specifically about version 6 but helped me understand why so many drastic changes in RxJS6 that aren't well explained in their own guide)Spurgeon
S
3

One thing I've learnt the hard way is being consistent

Watch out for mixing:

 import { BehaviorSubject } from "rxjs";

with

 import { BehaviorSubject } from "rxjs/BehaviorSubject";

This will probably work just fine UNTIL you try to pass the object to another class (where you did it the other way) and then this can fail

 (myBehaviorSubject instanceof Observable)

It fails because the prototype chain will be different and it will be false.

I can't pretend to understand exactly what is happening but sometimes I run into this and need to change to the longer format.

Spurgeon answered 9/2, 2018 at 0:57 Comment(2)
If someone can please explain this better please reply :-)Spurgeon
Visual Studio for instance will happily import from "rxjs" and merge definitions together where it seems you're better off doing them separately in the 'long' format.Spurgeon

© 2022 - 2024 — McMap. All rights reserved.