Observables

using 

RX.js 5

Nadav Sinai @ Misterbit

Nadav Sinai

  • Fullstack JS Web developer @ MisterBit 
  • Working as a consultant for firms such as Algotec, StartApp, Kaltura
  • Angular.js & Angular 2 expertise
  • Instructor of Angular 2 Courses

mail: ns@nadavsinai.com

web: nadavsinai.com

twitter: @nadavsinai

github: github.com/nadavsinai

JS is sync

let x = getValue();

for (let x of someIterable){
    ....
}


/// pull based
// we don't know when to pull

Web is Async

  • DomEvents

  • WebSockets

  • Ajax

  • ServiceWorker

  • WebWorker

  • GeoLocation

  • Fetch

Push values - async

let cb = (err,value) => {

}

doSomethingAsync(cb);

/// or better


doSomethingReturningPromise.then(value =>{


}).catch(errHandler)

But What about multiple value?

Single Multiple
Pull Function Iterator
Push Promise Observable


Observables are async primitive, just like promises

let myPromise = new Promise(function(resolve){
	resolve(42);
})

myPromise.then(value =>console.log(value));




let myObservable$ = Rx.Observable.create(function(observer){
	observer.next(42);
})

myObservable$.subscribe(value => console.log(value));



Like promises they contain the error logic and allow for one place of catching it.

let myPromise = new Promise(function(resolve,reject){
	resolve(42);
})

myPromise.then((value) => console.log(value),(error) => console.debug(error));

//or 
myPromise
.then((value) => console.log(value))
.catch((error) => console.debug(error));



let myObservable$ = Rx.Observable.create(function(observer){
	observer.next(42);
})

myObservable$.subscribe(value => console.log(value));


but they differ from promises too:

  • They can return multiple values

  • They can complete

  • They can be sync/async

  • They are lazy

  • They can be multicast/unicast

Multiple Values


let myObservable$ = Rx.Observable.create(function(observer){
	observer.next(42);
	observer.next(53);
})

myObservable$.subscribe(value => console.log(value));


let infinite = Rx.Observable.interval(1000);

infinite.subscribe(console.log)


Can complete


let myObservable$ = Rx.Observable.create(function(observer){
	observer.next(42);
	observer.next(53);
        observer.complete();
})

myObservable$.subscribe({next:(v)=>console.log(v),complete:()=>console.info('complete'));


let finite = Rx.Observable.interval(1000).take(5);

finite.subscribe((v)=>console.log(v),(e)=>console.error(e),(c)=>console.info(c));


Sync/async


export function getState(store:Store<any>):any {
	let state;

	store.take(1).subscribe(s => state = s); 

	return state;
}

Lazy*

var observable = Rx.Observable.create(function (observer) {
   console.log('In creation function');
  observer.next(1);
  observer.next(2);
  observer.next(3);
  setTimeout(() => {
    observer.next(4);
    observer.complete();
  }, 1000);
});

console.log('after observable setup');

// nothing happens...

multicast/unicast

  • publish makes an observale "hot"
  • When an observable is shared is it published upon first subscription and disposed upon last unsubscription

.share() === .publish().refCount()

Operators

  • Operators are what makes RxJs the lodash for async values
  • an operator basicaly returns an observable which subscribes to the source observable upon subscription, same for unsubscription, it can alter the values/timing along the way...

Anatomy of Observable

Observables are simple functions taking an observer and returning cancellation function.

Rx.Observable.create(function(observer){
			// can setup the data source here
//then can call next/error/completed on the observer here

return function(){

//can do any teardown logic here
}
});

Anatomy of Observer

the observer itself is just an interface :

interface Observer<T> {
  isUnsubscribed?: boolean;
  next: (value: T) => void;
  error: (err: any) => void;
  complete: () => void;
}

Rx.js Adds

Rx.js adds the following logic bits to every observable we create :

  1. If you pass an Observer doesn’t have all of the methods implemented, that’s okay.

  2. `next` can not be called  after a `complete` or an `error`

  3. Nothing can be called after source is unsubscribed.

  4. Calls to `complete` and `error` need to call unsubscription logic.

  5. If any  handler function throws an exception, unsubscription logic is called

Rx.js Adds

Rx.js adds the following logic bits to every observable we create :

  1. If you pass an Observer doesn’t have all of the methods implemented, that’s okay.

  2. `next` can not be called  after a `complete` or an `error`

  3. Nothing can be called after source is unsubscribed.

  4. Calls to `complete` and `error` need to call unsubscription logic.

  5. If any  handler function throws an exception, unsubscription logic is called

Rx.js has many helper function to create observables

 

Observable.from

Observable.of

Obserable.fromEvent

 

...has many ways to connect observables

 

Observable.merge

Observable.mergeMap

Observable.withLastestFrom

Observable.switchMap

 

And of course operators

​Which change the value

  • Observable.prototype.map()
  • Observable.prototype.filter()
  • Observable.prototype.distinctUntilChanged()
  • Observable.prototype.ignoreElements()

 

And of course operators

Or the timing of running the subcription:

Observable.prototype.debounce()

Observable.prototype.throttle()

Observable.prototype.takeUntil()

 

 

There 105 operators in the current rx.js beta.

 

You must add them to the build in order to use them

 

(import 'rxjs/add/operator/map')

 

 

Q & A

Observables using RX.js

By Nadav SInai

Observables using RX.js

Presentation about Observables and use with rx.js 5

  • 1,381