Chapter 9.2โ˜• 15 min read

Creating Observables

RxJS provides many ways to create Observables. From simple static values to timers, intervals, and custom streams.

01of() โ€” Emit Specific Values

of() emits each argument you pass one by one, then completes synchronously.

import { of } from 'rxjs';

// Emits three values then completes
of(1, 2, 3).subscribe(v => console.log(v));
// Output: 1 โ†’ 2 โ†’ 3 โ†’ (complete)

// Works with any types
of('Hyderabad', 'Biryani', 'Charminar').subscribe(v => console.log(v));

// Objects and arrays
of({ id: 1, name: 'Chicken Biryani' }, { id: 2, name: 'Mutton Biryani' })
  .subscribe(biryani => console.log(biryani.name));

"of = manual announcement โ€” bolo kya bolo, ek ek karke."

Use cases:

  • Returning a fallback value from catchError: return of([])
  • Testing: creating predictable Observable streams
  • Combining with other operators: startWith('loading')

Values are emitted synchronously โ€” all values are emitted in the same microtask, then the observable completes.

02from() โ€” Convert to Observable

from() converts an array, Promise, string, or any iterable into an Observable.

import { from } from 'rxjs';

// Array โ†’ Observable
from([10, 20, 30, 40]).subscribe(v => console.log(v));
// 10 โ†’ 20 โ†’ 30 โ†’ 40

// String โ†’ character stream
from('Hello').subscribe(v => console.log(v));
// H โ†’ e โ†’ l โ†’ l โ†’ o

// Promise โ†’ Observable
from(fetch('/api/biryani')).subscribe(response => {
  console.log('Response:', response);
});

// Set, Map, any iterable
from(new Set(['a', 'b', 'c'])).subscribe(v => console.log(v));

"from = converter โ€” koi bhi iterable ko stream bana do."

of vs from recap:

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

// BUT:
of([1, 2, 3]).subscribe(v => console.log(v)); // [1, 2, 3] โ€” array as single value!
from([1, 2, 3]).subscribe(v => console.log(v)); // 1, 2, 3 โ€” iterated!

of([1,2,3]) emits the entire array as ONE value. from([1,2,3]) iterates the array and emits each element separately.

03interval() and timer()

interval() and timer() create time-based Observables.

import { interval, timer } from 'rxjs';

// interval(period) โ€” emits 0, 1, 2... every N ms
interval(1000).subscribe(v => console.log(v));
// 0 (at 1s), 1 (at 2s), 2 (at 3s)... NEVER COMPLETES

// timer(dueTime) โ€” emits 0 after N ms, then completes
timer(3000).subscribe(v => console.log(v));
// 0 (at 3s), then complete

// timer(dueTime, period) โ€” emits 0 after N ms, then every M ms
timer(3000, 1000).subscribe(v => console.log(v));
// 0 (at 3s), 1 (at 4s), 2 (at 5s)... NEVER COMPLETES

"interval = metronome โ€” regular beat, kabhi nahi rukta."

"timer = alarm clock โ€” ek baar bajao ya repeat karo."

โš ๏ธ CRITICAL: Both interval() and timer() with period NEVER COMPLETE. They MUST be unsubscribed or used with operators like take(n) to prevent memory leaks.

// Safe pattern: take(5) auto-completes after 5 values
interval(1000).pipe(take(5)).subscribe(v => console.log(v));
// 0, 1, 2, 3, 4 โ†’ auto-completes
04Custom Observable with new Observable()

For full control, create an Observable manually with the Observable constructor.

import { Observable } from 'rxjs';

const customObservable = new Observable(subscriber => {
  // Emit values
  subscriber.next('Step 1: Order placed');
  subscriber.next('Step 2: Cooking started');
  subscriber.next('Step 3: Biryani ready!');

  // Complete the stream
  subscriber.complete();

  // Optional: Error
  // subscriber.error(new Error('Kitchen on fire!'));

  // Cleanup function โ€” runs on unsubscribe or complete
  return () => {
    console.log('Cleanup: cancelling order...');
  };
});

customObservable.subscribe({
  next: msg => console.log(msg),
  error: err => console.error(err),
  complete: () => console.log('Order delivered!'),
});

"Custom observable = apna TV channel banao โ€” jo chaho bolo."

Important methods:

  • subscriber.next(value) โ€” emit a value
  • subscriber.complete() โ€” end the stream
  • subscriber.error(err) โ€” emit an error
  • Return function โ€” teardown/cleanup logic (like removing event listeners)

Returning a cleanup function is optional but IMPORTANT โ€” it runs when the subscriber unsubscribes or when the stream completes. This is where you free resources, remove listeners, cancel timers.

05NEVER, EMPTY, throwError

Three special Observables for edge cases:

import { NEVER, EMPTY, throwError } from 'rxjs';

// NEVER โ€” never emits, never completes (infinite hang)
NEVER.subscribe({
  next: v => console.log(v), // NEVER CALLED
  complete: () => console.log('done'), // NEVER CALLED
});
// Useful for: testing race conditions, as source for switchMap

// EMPTY โ€” emits nothing, completes immediately
EMPTY.subscribe({
  next: v => console.log(v), // NEVER CALLED
  complete: () => console.log('done'), // CALLED IMMEDIATELY
});
// Useful for: default fallback in concat, as empty result

// throwError โ€” emits error, then dies
throwError(() => new Error('Bhai nahi hua')).subscribe({
  error: err => console.error(err.message), // CALLED
});
// Useful for: simulating errors, error fallback

"NEVER = blank screen, EMPTY = the end (nothing happened), throwError = error screen."

Real-world use cases:

  • EMPTY โ€” as fallback in catchError(() => EMPTY) โ€” silently swallows error
  • NEVER โ€” blocking navigation until a condition is met
  • throwError โ€” in testing, custom error scenarios

Key Takeaways

  • โœ… of(values) โ€” emit specific values synchronously, then complete
  • โœ… from(iterable) โ€” convert array/Promise/string to Observable (iterates each element)
  • โœ… interval(ms) โ€” emits every N ms (never completes); timer(delay, period) โ€” delayed start
  • โœ… new Observable(subscriber => { next, error, complete, return cleanup }) โ€” full control
  • โœ… NEVER (never emits), EMPTY (completes instantly), throwError (emits error)
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase