Observable vs Promise | What's the difference?

Last modified: April 2, 2020

Ask all your coding questions @ codequery.io

Observable vs Promise | What's the difference?
Observable vs Promise | Which is better?
Observable vs Promise | When to use Promise
Observable vs Promise | When to use Observable

Observables and promises are both used to handle async activity in JavaScript.

While an observable can do everything a promise can, the reverse is not true...

Here are the key differences between observables and promises:

Eager vs Lazy

A Promise executes when it is defined...

const myPromise = new Promise((resolve, reject) => {
  console.log('Promise firing!')
  resolve('Promise resolved.')
})
console.log('Before calling then...')
myPromise.then(res => console.log(res))

prints...

Promise firing!
Before calling then...
Promise resolved.

Notice how the Promise executes even before calling then(). As a result, we see Promise firing! before Before calling then....

Implementing the same thing with using Observables...

import { Observable } from 'rxjs'
const myObservable$ = new Observable(observer => {
  console.log('Observable firing!')
  observer.next('Observable called')
})
console.log('Before calling subscribe on Observable')
myObservable$.subscribe({
  next: console.log
})

prints...

Before calling subscribe on Observable
Observable firing!
Observable called

Notice how the Observable executes only after calling subscribe() on myObservable$

Sync vs Async

A Promise is always asynchronous...

const myPromise = new Promise((resolve, reject) => {
  resolve('Promise resolved.')
})
console.log('Before calling then...')
myPromise.then(res => console.log(res))
console.log('After calling then...')

prints...

Before calling then...
After calling then on Promise (proof of being always async)
Promise resolved.

Notice how the Promise behaves asynchronously even when we resolve it immediately. The rest of the code runs before the Promise resolves.

Let's look at the same example implemented with Observables...

import { Observable } from 'rxjs'
const myObservable$ = new Observable(observer => {
  observer.next('Observable called')
})
console.log('Before calling subscribe')
myObservable$.subscribe({
  next: console.log
})
console.log('After calling subscribe')

prints...

Before calling subscribe
Observable called
After calling subscribe

Notice how the code runs synchronously when using Observables...

We can also achieve asynchronous behavior using Observables...

const myObservable$ = new Observable(observer => {
  setTimeout(() => {
    observer.next('Observable called')
  }, 5000)
})

By wrapping our call to observer.next() in a setTimeout() function we can make the observable behave asynchronously.

Promises only behave asynchronously....Observables can behave both ways.

RxJs Operators

Unlike promises, Observables are not native to JavaScript. Libraries like Angular and React utilize the RxJs library to implement the observable design pattern.

The RxJs library includes it's own implementation of the Observable class along with helpful operators for manipulating streams of data...

import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
const myObservable$ = new Observable(observer => {
    observer.next(2)
});
const mappedValues = myObservable$.pipe(map(x => x * 2))
mappedValues.subscribe({
  next: console.log
});

prints...

4

Notice how we've utilized the map operator to perform some extra operations on the values read from myObservable$.

While you could use vanilla JS to iterate through the emitted values in a similar fashion, RxJs operators make it easier to work with values as they are emitted.

"Cancellable"

You can cancel an Observable by unsubscribing...

myObservable$.unsubscribe()

You can't cancel a Promise.

Multiple Values

Observables can emit multiple values...

const myObservable$ = new Observable(observer => {
    observer.next(1)
    observer.next(2)
    observer.next(3)
});
myObservable$.subscribe({
  next: console.log
});

prints...

1
2
3

The same is not true for a Promise...

const myPromise = new Promise((resolve, reject) => {
  resolve(1)
  resolve(2)
  resolve(3)
})
myPromise.then(res => console.log(res))

prints...

1

Once a Promise resolves, that's it. You can't emit multiple values with a Promise.

Conclusion

Observables and Promises can both be used to handle async activity in JavaScript. While an Observable can do everything a Promise can do, the reverse is not true.

For a more in-depth discussion, check out the difference between Observable and Promise.

You might also like: