skip to content

Stream Creation Functions

Functions such as of, from, fromEvent, interval, timer and defer turn values, promises, events and time into streams. Interviewers ask which one emits synchronously and when each one completes.

part ofRxJSoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In RxJS, what is the difference between of([1, 2, 3]) and from([1, 2, 3]), and what inputs does from() accept?

level: juniorimportance: must knowfreq 70%

answer

  1. arguments versus contents
  2. one array value or three numbers
  3. ObservableInput
  4. promises, iterables, streams

basics

~20 s

of([1, 2, 3]) emits the array as one value; from([1, 2, 3]) emits 1, 2 and 3 separately. from() converts any ObservableInput - arrays, iterables, promises, async iterables, ReadableStreams or Observables - into an Observable.

solid answer

~40 s

`of(...values)` emits each **argument** as-is, then completes, so `of([1, 2, 3])` emits a single array value and `of(1, 2, 3)` emits three numbers. `from(input)` **unpacks** one input: `from([1, 2, 3])` emits 1, 2, 3 and completes. `from()` accepts any `ObservableInput`: an Observable (returned as-is), an object implementing `Symbol.observable`, an array or array-like (so a string emits its characters), a Promise or other thenable, an async iterable, an iterable such as a `Map` or generator, or a `ReadableStream`. Anything else throws a `TypeError` when `from()` is called. `of` and `from` over arrays or iterables emit synchronously during `subscribe()`; `from(promise)` emits later, when the promise resolves.

code

ts · 17 lines
ts
import { from, of } from 'rxjs';

of([1, 2, 3]).subscribe((v) => console.log('of:', v));
// of: [1, 2, 3]

from([1, 2, 3]).subscribe((v) => console.log('from:', v));
// from: 1
// from: 2
// from: 3

from(new Map([['a', 1]])).subscribe((v) => console.log('map entry:', v));
// map entry: ['a', 1]

from(Promise.resolve(42)).subscribe((v) => console.log('promise:', v));
console.log('after subscribe');
// after subscribe
// promise: 42

go deeper

for a junior

Recall that of emits its arguments and from unpacks one input, and give the array example both ways.

for a middle

List the ObservableInput kinds from() accepts, and say which ones emit synchronously and which emit when a promise resolves.

for a senior

Watch for code that relies on from(promise) being lazy, and for per-item logic silently receiving whole arrays because of() was used.

for a principal

Encourage APIs that accept ObservableInput rather than Observable only, so callers can pass arrays or promises without wrapping them.

## Two creation functions, two jobs RxJS's **creation functions** build an `Observable` from something that already exists. `of` and `from` are the two most used, and they are easy to confuse because both can take an array. - **`of(...values)`** treats each argument as one value. It emits the arguments in order, then completes. - **`from(input)`** takes a single input and converts it, **unpacking** whatever it contains. | Expression | Emits | Then | |---|---|---| | `of(1, 2, 3)` | `1`, `2`, `3` | complete | | `of([1, 2, 3])` | `[1, 2, 3]` (one value) | complete | | `from([1, 2, 3])` | `1`, `2`, `3` | complete | | `of()` | nothing | complete | | `from('abc')` | `'a'`, `'b'`, `'c'` | complete | Under the hood, `of` simply calls `from` on its argument list, which is why `of(1, 2, 3)` and `from([1, 2, 3])` behave the same. ## What from() accepts `from()` accepts the type RxJS calls **`ObservableInput`**. RxJS 7 checks the input in this order: 1. an RxJS `Observable` - returned unchanged; 2. an object implementing **`Symbol.observable`** (an interop observable from another library); 3. an **array-like** value - arrays, `arguments`, typed arrays and strings; 4. a **Promise** or any thenable - it emits the resolved value then completes, or errors on rejection; 5. an **async iterable** - such as an async generator; 6. an **iterable** - a `Set`, a `Map` (yielding `[key, value]` pairs) or a generator; 7. a **ReadableStream**-like object. If none of these match - a plain object, a number, `null` - `from()` throws a `TypeError` whose message reads "You provided ... where a stream was expected". The check happens when `from()` is **called**, not when the result is subscribed, so the error surfaces at the call site. The same `ObservableInput` type is what operators accept wherever they need an inner source, which is why a function that returns a Promise or an array can be used almost anywhere RxJS expects an Observable. ## Timing and completion Both functions **complete** once the input is exhausted, but they differ in when values arrive: - `of(...)`, `from(array)` and `from(iterable)` emit **synchronously**: every value and the completion are delivered before `subscribe()` returns. - `from(promise)` emits **asynchronously**, when the promise's reaction runs - even for a promise that has already resolved. - `from(asyncIterable)` and `from(readableStream)` emit asynchronously as items become available. The array loop also checks whether the subscriber has closed before each value, so an operator such as `take(2)` downstream stops a large array early instead of walking all of it. ## Common mistakes - Writing `of(items)` when the code needs one emission per item. The subscriber receives the whole array once, and per-item operators never see individual items. - Writing `from(items)` when the code needs the array as a single value - for example, when feeding a list into a stream of "current list" states. - Passing a plain object to `from()` and expecting its properties to be emitted. Objects are not iterable; use `from(Object.entries(obj))` instead. - Believing `from(promise)` makes the promise lazy. The promise has already started; `from` only adapts its result. Deferring the promise's creation is `defer`'s job. ## from() as a normaliser Because `from()` returns an RxJS `Observable` unchanged, it is cheap to call on something that might already be one. That makes it a handy normaliser at API boundaries: - a helper that accepts `ObservableInput<T>` can call `from(input)` once and then use operators, whatever the caller passed; - an Observable from another library that implements `Symbol.observable` is adapted into an RxJS one, so RxJS operators can be applied to it; - a callback that sometimes returns an array and sometimes a promise can be handled by the same code path. ## Deprecated forms to recognise Older code passes a scheduler as the last argument - `of(1, 2, 3, asyncScheduler)` or `from(array, scheduler)`. That argument is deprecated since RxJS 6.5 and scheduled for removal in v8; the replacement is `scheduled(input, scheduler)`. Explicit type arguments on `of<T>()` with no values are also deprecated. ## In an interview The one-line answer is "`of` emits its arguments, `from` unpacks its input". A strong candidate adds the list of `ObservableInput` types, notes that `from(promise)` is asynchronous while `of` and `from(array)` are synchronous, and knows that `from()` on an unsupported value throws immediately rather than erroring through the stream.

  • In RxJS, what happens if you call from() with a plain object such as { a: 1 }?
    It throws a `TypeError` immediately, at the `from()` call, because a plain object is not an `ObservableInput`: it is not array-like, not a thenable and not iterable. The message says an Observable, Promise, ReadableStream, Array, AsyncIterable or Iterable was expected. To stream its properties, pass `Object.entries(obj)` to `from()` instead.
  • In RxJS 7, how do you make of(1, 2, 3) emit asynchronously now that the scheduler argument is deprecated?
    Use `scheduled([1, 2, 3], asyncScheduler)`, which RxJS added as the replacement for the scheduler argument on `of` and `from`. Each value is then delivered through the scheduler instead of inside the `subscribe()` call. How the individual schedulers differ is a separate topic.

saying these in an interview costs you the question

  • of([1, 2, 3]) emits 1, 2 and 3 as separate values.
  • from() over a plain object emits each property.
  • from(promise) makes the promise lazy, so it starts on subscribe.
  • of and from always emit asynchronously.
  • from() on an unsupported value errors through the stream when subscribed.
open as a page

In RxJS, how do interval(5000), timer(5000) and timer(0, 5000) differ, and which suits polling that must fire immediately?

level: middleimportance: must knowfreq 58%

basics

~20 s

interval(5000) emits 0, 1, 2... every 5 s, first after 5 s, forever. timer(5000) emits 0 once after 5 s and completes. timer(0, 5000) emits at once, asynchronously, then every 5 s - the usual choice for polling.

open as a page

In RxJS, what does fromEvent(button, 'click') do when you subscribe and unsubscribe, and when does the resulting stream complete?

level: juniorimportance: should knowfreq 55%

basics

~20 s

fromEvent adds a click listener to the button on each subscribe, emits every event object, and removes that listener on unsubscribe. It never completes on its own, so something must unsubscribe or a take-style operator must end it.

open as a page

In RxJS, why does from(fetch(url)) not send a new request per subscription, and how does defer() change that?

level: middleimportance: should knowfreq 45%

basics

~20 s

fetch(url) starts the request as soon as the expression is evaluated, and from() only adapts that one promise, so every subscriber gets the same response. defer(() => fetch(url)) calls the factory on each subscribe, sending one request per subscription and none before.

open as a page

In RxJS, which creation functions emit synchronously inside subscribe(), and what bugs can that synchronous emission cause in real code?

level: seniorimportance: should knowfreq 38%

basics

~20 s

of, from over arrays or iterables, range and EMPTY deliver all values and completion before subscribe() returns; from(promise), interval and timer deliver later. Synchronous delivery breaks code that uses the subscription variable in its callback or that assumes asynchrony.

open as a page