232

Is the only difference between Observable.of and Observable.from the arguments format? Like the Function.prototype.call and Function.prototype.apply?

Observable.of(1,2,3).subscribe(() => {})
Observable.from([1,2,3]).subscribe(() => {})
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
xiaoke
  • 3,272
  • 2
  • 17
  • 20

11 Answers11

275

It is important to note the difference between of and from when passing an array-like structure (including strings):

Observable.of([1, 2, 3]).subscribe(x => console.log(x));

would print the whole array at once.

On the other hand,

Observable.from([1, 2, 3]).subscribe(x => console.log(x));

prints the elements 1 by 1.

For strings the behaviour is the same, but at character level.

Tsvetan Ovedenski
  • 3,328
  • 1
  • 16
  • 9
  • What if Observable.of(1, 2, 3).subscribe(x => console.log(x)); – xiaoke Sep 14 '17 at 22:28
  • 5
    @xiaoke Then surely it is 3 separate emissions (1, then 2, then 3). – Tsvetan Ovedenski Sep 15 '17 at 06:40
  • 1
    @xiaoke 1, 2, 3 is a stream of data emitted one after the other(as these values are not wrapped inside a data structure) so the behaviour of such a stream would be same in case of 'of' or 'from'. However an array is single stream of data when passed to 'of' and one by one stream of data when passed to 'from' as mentioned in the answer as well. – utkarsh-k Nov 27 '21 at 08:01
149

Not quite. When passing an array to Observable.from, the only difference between it and Observable.of is the way the arguments are passed.

However, Observable.from will accept an argument that is

a subscribable object, a Promise, an Observable-like, an Array, an iterable or an array-like object to be converted

There is no similar behaviour for Observable.of - which always accepts only values and performs no conversion.

cartant
  • 57,105
  • 17
  • 163
  • 197
53

One line Difference :

       let fruits = ['orange','apple','banana']

from : Emit the items one by one of array. For example

    from(fruits).subscribe(console.log) // 'orange','apple','banana'

of : Emit the whole array at once. For example

 of(fruits).subscribe(console.log) //  ['orange','apple','banana']

NOTE: of operator can behave as from operator with spread operator

 of(...fruits).subscribe(console.log) //  'orange','apple','banana'
mabdullahse
  • 3,474
  • 25
  • 23
24

Another interesting fact is Observable.of([]) will be an empty array when you subscribe to it. Where as when you subscribe to Observable.from([]) you wont get any value.

This is important when you do a consecutive operation with switchmap.

Ex: In the below example, I am saving a job and then sites, and then comments as a stream.

.do((data) => {
            this.jobService.save$.next(this.job.id);
        })
        .switchMap(() => this.jobService.addSites(this.job.id, this.sites)
            .flatMap((data) => {
                if (data.length > 0) {
                    // get observables for saving
                    return Observable.forkJoin(jobSiteObservables);
                } else {
                    **return Observable.of([]);**
                }
            })).do((result) => {
            // ..
        })
        .switchMap(() => this.saveComments())
....

if there's no site to save, ie; data.length = 0 in addSite section, the above code is returning Observable.of([]) and then goes to save comments. But if you replace it with Observable.from([]), the succeeding methods will not get called.

rxfiddle

Josf
  • 776
  • 1
  • 8
  • 21
  • This is due to function signature difference: The equivalent of `Observable.from([])` would be `Observable.of()` – without an empty array inside! If you provide an empty array inside `…of()`, then you do provide a value (1 value, an empty array that is). The `from`-equivalent of that would be `Observable.from([ [] ])` (an array with one empty array) – Frank N Nov 03 '22 at 16:49
21

of will emit all values at once

from will emit all values one by one

of with spread operator = from operator

Muhammad Bilal
  • 1,840
  • 1
  • 18
  • 16
9

from: Create observable from array, promise or iterable. Takes only one value. For arrays, iterables and strings, all contained values will be emitted as a sequence

const values = [1, 2, 3];
from(values); // 1 ... 2 ... 3

of: Create observable with variable amounts of values, emit values in sequence, but arrays as single value

const values = [1, 2, 3];
of(values, 'hi', 4, 5); // [1, 2, 3] ... 'hi' ... 4 ... 5
5
  1. from returns notification in chunks i.e. one by one. for eg: from("abcde") will return a => b => c => d => e
  2. of returns complete notification. for eg: of("abcde") will return abcde.

https://stackblitz.com/edit/typescript-sckwsw?file=index.ts&devtoolsheight=100

Udit Gandhi
  • 337
  • 4
  • 6
2

The from operator takes source of events. from(source)

let array = [1,2,3,4,5]
from(array); //where array is source of events, array[of events]


let promise = new Promise(function(resolve, reject) {
  // executor (the producing code, "singer")
});
from(promise); //where promise is source of event, promise(of event)





let observable = Observable.create(function(observer) {
  observer.next(1);
  observer.next(2);
  observer.next(3);
  observer.next(4);
  observer.next(5);
  observer.complete();
});
from(observable); // where obsservable is source of events. 

The of operator takes intividual events. of(event1, event2, event3)

of(1,2,3,4,5); // where 1,2,3,4,5 are individual events
ParagFlume
  • 959
  • 8
  • 17
0

I found it easier to remember the difference when the analogy with .call / .apply methods came into my mind.

You can think of it this way:

  • normally, all arguments, that are passed separately (separated by comma), are also emitted separately, in the order they were passed. of() just emits all arguments one by one as they are (like .call method passes arguments to the function it was called on)
  • from() is like .apply in a sense that it can take an array of values as an argument, and convert array elements into separate arguments, separated by comma.

So, if you have an array and want each element to be emitted separately, you can use from() or get the same behavior by using of() with spread operator, like of(...arr).

It's bit more complicated then that (from can also take observables) but with this analogy it will probably be easier to remember the main difference.

Yaroslav Larin
  • 209
  • 2
  • 6
0

Yes it is true that of will result in an output in single go and from will happen one at a time. But there is more difference related to number of arguments and type of arguments.

You can pass any number of arguments to the Of. Each argument emitted separately and one after the other. It sends the Complete signal in the end.

However you can send only one argument to the from operator and that one argument should be a type of

  • an Array,
  • anything that behaves like an array
  • Promise
  • any iterable object
  • collections
  • any observable like object

For example you can send a raw object like

myObj={name:'Jack',marks:100}

to of operator to convert to Observable.

obj$:Observable<any> = of(myObj);

but you can not send this raw object myObj to from operator simply because it is not iterable or array like collection.

for more detail : visit here

J. Doe
  • 69
  • 7
-1

from operator may accept one of

promises iterable arrays observable

from emits each individual item from the observable , can also do conversions.

of operator takes in the raw value and emits the value from the observable.

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

const ofObs = of([1,2,3]);
const fromObs = from([2,3,4]);

const basicObs = Observable.create(observer=>{
    observer.next(100);
    observer.next(200);
    observer.next(300);
})
const promise = new Promise((resolve,reject)=>{
    resolve(100);
})

const array = [1,2,3];
const iterbale  = "Dhana";

// const myObs = from(ofObs);//possible and can emit individual item value everytime 1, then ,2 , then 3
// const myObs = from(fromObs);//possbile and can emit individual item value everytime 1, then ,2 , then 3
// const myObs = from(basicObs);//possbile and can emit individual item value everytime 100, then ,200 , then 300
const myObs = from(promise);//possible can emit value 100
// const myObs = array(promise);//possible and can emit individual item value everytime 1, then ,2 , then 3
// const myObs = iterable(promise);//possible and can emit individual item value everytime D then h then a then n then a


myObs.subscribe(d=>console.log(d))



import {from, of} from 'rxjs';

const basicOf1 = of([1,2,3,4,5,6]) // emits entire array of events
const basicfrom1 = from([1,2,3,4,5,6]) //emits each event at a time

const basicOf2 = of(1,2,3,4,5,6) // emits each event at a time
// const basicfrom2 = from(1,2,3,4,5,6) //throws error
//Uncaught TypeError: number is not observable

const basicOf3 = of(...[1,2,3,4,5,6]) // emits each event at a time
const basicfrom3 = from(...[1,2,3,4,5,6]) //throws error
//Uncaught TypeError: number is not observable
basicOf3.subscribe(d=>console.log(d))

Here is the link to codepen

Dhana
  • 694
  • 13
  • 18