Operators & Subjects

Preview — 3 of 10 questions

What is the key difference between switchMap and mergeMap?

javascript
// switchMap — cancels previous inner Observable on new emission
// ✅ Ideal for search-as-you-type (abort stale requests)
searchControl.valueChanges.pipe(
  debounceTime(300),
  switchMap(query => this.http.get<Result[]>(`/api/search?q=${query}`)),
  // If user types again before response arrives, old request is unsubscribed
).subscribe(results => this.results = results);

// mergeMap — all inner Observables run concurrently
// ✅ Ideal for independent parallel operations (file uploads)
fileQueue$.pipe(
  mergeMap(file => this.uploadService.upload(file)),
  // All uploads run in parallel
).subscribe(result => this.completed.push(result));

// concatMap — queues inner Observables, runs sequentially
// ✅ Ideal for ordered operations (save queue)
saveQueue$.pipe(
  concatMap(item => this.http.post('/api/save', item)),
).subscribe();
AswitchMap cancels the previous inner Observable when a new value arrives; mergeMap subscribes to all inner Observables concurrently
BswitchMap preserves order; mergeMap does not
CmergeMap is deprecated in favor of switchMap in RxJS 7
DswitchMap is for HTTP GET; mergeMap is for HTTP POST

Why are debounceTime and distinctUntilChanged typically combined for search inputs?

javascript
@Component({
  template: `<input [formControl]="searchControl">`,
  standalone: true,
  imports: [ReactiveFormsModule],
})
export class SearchComponent implements OnInit {
  searchControl = new FormControl('');

  ngOnInit() {
    this.searchControl.valueChanges.pipe(
      debounceTime(300),          // wait 300ms after last keystroke
      distinctUntilChanged(),     // don't search if value is same as last
      filter(query => (query?.length ?? 0) >= 2),  // minimum chars
      switchMap(query =>
        this.searchService.search(query!).pipe(
          catchError(() => of([]))
        )
      ),
    ).subscribe(results => this.results = results);
  }
}
AdebounceTime deduplicates values; distinctUntilChanged adds a delay
BdebounceTime waits for the user to stop typing before emitting; distinctUntilChanged prevents re-triggering searches when the value hasn't actually changed
CThey cancel each other out and are only combined for backwards compatibility
DdebounceTime is required by the HTTP client to batch requests; distinctUntilChanged is optional

When does combineLatest emit?

javascript
import { combineLatest } from 'rxjs';

const userId$ = this.authService.userId$;   // emits current user ID
const filters$ = this.filterState$;          // emits current filter settings

// Emits [userId, filters] whenever either changes (after both have emitted once)
combineLatest([userId$, filters$]).pipe(
  switchMap(([userId, filters]) =>
    this.dataService.getData(userId, filters)
  ),
).subscribe(data => this.data = data);

// Example: wait until both dropdowns are selected
combineLatest([
  this.countryControl.valueChanges.pipe(startWith(null)),
  this.cityControl.valueChanges.pipe(startWith(null)),
]).pipe(
  filter(([country, city]) => country !== null && city !== null),
).subscribe(([country, city]) => this.loadData(country!, city!));
AWhen any one of its source Observables emits, regardless of others
BWhen all source Observables complete
COnly when ALL source Observables have emitted at least one value, and then on every subsequent emission from any source
DWhen the first source Observable emits

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.