Creating Observables
RxJS provides many ways to create Observables. From simple static values to timers, intervals, and custom streams.
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.
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.
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-completesFor 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 valuesubscriber.complete()โ end the streamsubscriber.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.
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 incatchError(() => EMPTY)โ silently swallows errorNEVERโ blocking navigation until a condition is metthrowErrorโ 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)
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login