DEV Community

kirandeepjassal-crypto
kirandeepjassal-crypto

Posted on Originally published at prepstack.co.in

Angular Interview Questions for Senior Developers in 2026 — Change Detection, RxJS, Signals & Performance (Deep Answers)

Junior Angular interviews ask "what is a component." Senior interviews ask why your dashboard re-runs change detection thousands of times a second, why a typeahead fires a request per keystroke and shows stale results, and why that subscription leaks memory until the tab crawls. Angular is a big, opinionated framework, and seniority is knowing the machinery underneath — change detection, RxJS, the new signals model, and where performance goes to die.

This is 30 questions across four blocks. Each answer is a short answer you could say in one breath, a deep dive into the mechanism (with code), and the senior signal the interviewer is listening for. Examples use modern Angular (v17+: standalone, signals, the new control flow) and are grounded in Mattrx — a real multi-tenant marketing-analytics platform whose internal admin console is built in Angular.

The lens for all 30

A junior uses the APIs; a senior understands change detection, the reactivity model, and RxJS semantics — and designs to work with them. "Why is the app janky?" gets a shrug from a junior and "default CD is re-checking a 2,000-node tree on every mousemove — OnPush + signals cut it to the subtree that changed" from a senior.

Block B highlight — how change detection actually works

Angular runs CD to sync model → DOM. Zone.js monkey-patches async APIs (events, timers, XHR) so after any async task, Angular walks the component tree top-down and dirty-checks each binding.

async event (click / http / timer)
  -> zone.js notifies Angular
  -> CD walks the component tree top-down, checks each binding
  -> updates the DOM where a bound value changed
Enter fullscreen mode Exit fullscreen mode

Default vs OnPush: Default checks every component every run. OnPush skips a component unless an @Input reference changed, an event fired inside it, or an async-bound observable emitted. On big trees OnPush is the single biggest perf lever.

@Component({
  selector: 'campaign-list',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: \`@for (c of campaigns(); track c.id) { <campaign-row [campaign]="c" /> }\`,
})
export class CampaignListComponent {
  campaigns = input.required<Campaign[]>();   // new reference -> this subtree is checked
}
Enter fullscreen mode Exit fullscreen mode

Senior signal: you default to OnPush, know it relies on immutable inputs, and can name the three triggers that still run it.

Block C highlight — the RxJS flattening operators

The high-stakes RxJS question. They all map to an inner observable and flatten, differing in how they handle overlap:

switchMap:  new value -> CANCEL previous, start new     (search/typeahead)
concatMap:  queue -> run one after another, in order    (ordered writes)
mergeMap:   run all concurrently                        (independent parallel)
exhaustMap: ignore new while one runs                   (dedupe rapid submits)
Enter fullscreen mode Exit fullscreen mode
// Typeahead: switchMap cancels the in-flight request when a new term arrives -> no stale results.
this.search.valueChanges.pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(term => this.api.search(term)),
).subscribe(r => this.results.set(r));
Enter fullscreen mode Exit fullscreen mode

Pick switchMap for search, exhaustMap for submit, concatMap for ordered writes, mergeMap for independent parallel work. Most "senior" candidates get tripped here.

Block C highlight — signals vs RxJS

Signals are Angular's synchronous reactive primitive — a value you read as a function, with computed() for derived values and effect() for side effects. They power fine-grained, zoneless CD. RxJS stays for async streams/events; signals are for synchronous state. Bridge with toSignal / toObservable.

count = signal(0);
double = computed(() => this.count() * 2);          // recomputes only when count changes
constructor() { effect(() => console.log(this.count())); }
this.count.update(n => n + 1);                       // triggers dependents precisely
Enter fullscreen mode Exit fullscreen mode

And preventing leaks — prefer the async pipe or takeUntilDestroyed() over manual ngOnDestroy bookkeeping:

this.api.pollKpis().pipe(takeUntilDestroyed()).subscribe(k => this.kpis.set(k));
Enter fullscreen mode Exit fullscreen mode

The through-line

Angular is fast and maintainable when you cooperate with change detection (OnPush, immutability, signals), pick the right RxJS operator by its overlap semantics, and tear down subscriptions (async pipe / takeUntilDestroyed). Fight it and you get jank and leaks. Answer each question with the mechanism and the failure it prevents, and you sound like someone who has shipped and profiled a real Angular app.

The full guide has all 30 — components & DI, change detection & performance, RxJS & state, and routing/forms/testing/production — each with the short answer, the deep dive with code, and the exact senior signal:

https://prepstack.co.in/blog/angular-senior-interview-questions-change-detection-rxjs-signals-performance-deep-answers

Originally published on PrepStack.

Top comments (0)