Observable is more powerful way of handling http asynchronous requests.
A Promise handles a single event when an async operation completes or fails.
Note: There are Promise libraries out there that support cancellation, but ES6 Promise doesn’t so far.
An Observable is like a Stream (in many languages) and allows to pass zero or more events where the callback is called for each event.
Promises:
returns a single value
not cancellable
Promises are eager while obeservable are lazy
Observables:
works with multiple values over time
cancellable
supports map, filter, reduce and similar operators
proposed feature for ES 2016
use Reactive Extensions (RxJS)
an array whose items arrive asynchronously over tim
There are also powerful operators like retry(), or replay().
Single value vs multiple values
Promises are most commonly used to handle HTTP requests. In this model, you make a request and then wait for a single response. You can be sure that there won’t be multiple responses to the same request.
const numberPromise = new Promise((resolve) => {
resolve(5);
});
numberPromise.then(value => console.log(value));
It will print 5.
Promise is always resolved with the first value passed to the resolve function and ignores further calls to it:
const numberPromise = new Promise((resolve) => {
resolve(5);
resolve(10);
});
numberPromise.then(value => console.log(value));
// still prints only 5
On the contrary, Observables allow you to resolve (or, as we say, “emit”) multiple values. Here is how it would look:
const numberObservable = new Observable((observer) => {
observer.next(5);
observer.next(10);
});
numberObservable.subscribe(value => console.log(value));
// prints 5 and 10
Let’s for example see how wrapping setInterval in Observable would look like.
const secondsObservable = new Observable((observer) => {
let i = 0;
setInterval(() => {
observer.next(i++);
}, 1000);
});
secondsObservable.subscribe(value => console.log(value));
// logs:
// 0
// 1
// 2
// and so on, every second
Eager vs lazy
Let’s rewrite setInterval example
const secondsPromise = new Promise((resolve) => {
let i = 0;
setInterval(() => {
resolve(i++);
}, 1000);
});
We have a problem here. Even though no one is listening for these numbers (we are not even logging them here),
setInterval is still called immediately at the moment of Promise creation. We are wasting resources, emitting values that no one will listen to. This happens because Promise constructor immediately calls function passed to it.
On the contrary test following, Observable based, code:
const observable = new Observable(() => {
console.log('I was called!');
});
This time nothing happens. This is because while Promises are eager, Observables are lazy. Function passed to Observable constructor gets called only when someone actually subscribes to an Observable:
Not cancellable vs cancellable
Here is the code of observable for cancellation
const subscription =
secondsObservable.subscribe(value => console.log(value));
subscription.unsubscribe();
ngModel
directive.