What Sitting Through Dozens of Frontend Interviews Actually Taught Me
I want to be honest with you about something.
After self-teaching React for months, building projects, and feeling genuinely confident in my skills, I walked into my first set of technical interviews and got absolutely humbled.
Not because I didn't know JavaScript. I did. Not because my React components were bad. They weren't.
I failed because the interviewers weren't just testing my framework knowledge — they were testing whether I understood the web itself. And I didn't.
This post is everything I wish someone had told me before I started that interview grind. These aren't concepts from a textbook. They're the exact topics that came up again and again, across company after company, until I finally built a mental model solid enough to talk about them confidently.
The Painful Realization
The moment it clicked for me was during an interview where the interviewer asked a simple question:
> "When a user types a URL and hits Enter, walk me through exactly what happens."
I said something about DNS and the server sending HTML back. That was it.
The interviewer smiled, said "interesting", and moved on. I bombed that round.
The correct answer involves DNS resolution, TCP handshake, TLS negotiation, HTTP request/response, the critical rendering path, JavaScript parsing, and layout/paint. I had used all of these things without ever understanding they existed.
That was my wake-up call.
🔴 The Topics I Had to Learn First (Absolute Highest Priority)
1. The Browser Rendering Pipeline
This came up in literally every company after a certain level. Not as trivia — as a performance debugging question.
What I had to learn:
- Critical Rendering Path: HTML → DOM, CSS → CSSOM, merge into Render Tree, then Layout → Paint → Composite
- Reflow vs. Repaint: Reading
offsetWidthinside a loop causes reflow on every iteration — I had done this in my own projects without knowing - The Event Loop: Call stack → Web APIs → Microtask Queue (Promises) → Macro Task Queue (setTimeout) — and why a resolved Promise fires before
setTimeout(fn, 0)
requestAnimationFrame. Once I understood compositing, I switched to transform and opacity only — which run on the GPU — and never had that issue again.
// Before: Triggering layout (Slow)
element.style.width = scrollY + "px";
// After: Triggering composite only (Fast)
element.style.transform = `scaleX(${scrollY / 100})`;
2. HTTP Is Not Just fetch()
I knew how to call an API. I had no idea what was actually happening underneath.
The concepts that saved me:
- HTTP/1.1 vs HTTP/2: Six connection limits per domain in HTTP/1.1 caused my image-heavy pages to load slowly. HTTP/2 multiplexing solved it.
- Status codes with intent: The difference between
301(permanent redirect, browser caches it) and302(temporary, browser re-checks every time) changed how I handled routing - CORS: I used to just Google "CORS fix" and paste the first answer. Now I understand it's a browser security feature, not a server one — and why the preflight
OPTIONSrequest exists Cache-Controlheaders:no-cache,no-store,max-age,stale-while-revalidate— these determine whether your fast API feels fast to the second user, not just the first
3. The JavaScript Engine Internals I Was Missing
I thought I knew JavaScript. I knew the syntax. The engine was a different story.
- Closures creating memory leaks: I had written components that held references to DOM nodes through stale closures inside
useEffect. I didn't know they were leaks — I just called it "a bug I couldn't find" thisbinding: I failed a coding round by writingthis.handleClickas a class method call without.bind(this)in a constructor. I knew hooks, but didn't understand why the old pattern worked the way it did- Prototype chain: Every interviewer who asks "how does inheritance work in JS?" is not asking about
class— they want prototypes - Execution context: Understanding scope chains made me realize why my old "global variable" hacks were dangerous
🟠 The Second Wave of Pain (What Mid-Level Interviews Test)
4. Web Security — The Topic I Was Most Embarrassed About
I had shipped forms with user input to production and genuinely did not know what XSS was.
- XSS (Cross-Site Scripting): When you trust user input and render it to the DOM, an attacker can inject a
<script>tag. React's JSX escapes strings by default — butdangerouslySetInnerHTMLbypasses that entirely. I had used it once "for convenience." - CSRF: If your site uses cookie-based auth, an attacker can trick a logged-in user into making requests to your server from another domain.
SameSite=Laxcookie attribute is the modern defense. - CSP (Content Security Policy): A response header that tells the browser which scripts/styles to trust. It's the last line of defense against XSS, and most junior devs have never seen it.
dangerouslySetInnerHTML with unescaped user content in a notes app. That was... uncomfortable.
5. Performance Is a Feature, Not a Finish Line
I thought performance was about "Lighthouse score." It's actually about user psychology.
The real framework I built:
- Core Web Vitals aren't arbitrary: LCP is about perceived loading speed. CLS is about visual stability — if your button jumps before the user clicks, they might click the wrong thing. INP is about responsiveness.
- Code splitting: I shipped 400KB of JavaScript on the initial load because I imported a charting library at the top level.
React.lazy+Suspensecut that to 80KB. - Image optimization:
srcsetandsizesare not optional. They're how you ship the right image to the right screen.next/imagedoes this automatically — it was one of the main reasons I migrated my portfolio to Next.js.
6. Async Patterns Beyond async/await
I knew how to use async/await. I didn't know when to use which async pattern.
The questions that tripped me up:
Promise.allvsPromise.allSettled:Promise.allfails fast — if one promise rejects, the whole thing rejects.Promise.allSettledwaits for all, giving you a results array. UseallSettledwhen you want to know about every failure, not just the first one.- Debounce vs Throttle: I could explain them in English but couldn't implement them. The interviewer asked me to write debounce from scratch. My first attempt was wrong. My second attempt was also wrong. I now know this by heart.
- WebSockets vs SSE: SSE is one-directional (server → client) over regular HTTP. WebSockets are bidirectional but need a dedicated connection. For a live notification feed, SSE is simpler and often enough — you don't need WebSockets.
🟡 The Stuff That Made Me Look Senior Before I Was (Worth the Investment)
7. Accessibility — The Most Underrated Differentiator
Almost no fresher talks about accessibility. Which means if you can, you immediately stand out.
What I learned:
- A
<div onClick>is not accessible. It has no keyboard focus, no role, no accessible name. A<button>gets all of that for free. aria-label,aria-describedby,role, andtabIndexexist because sometimes semantic HTML alone isn't enough- Focus management in modals: when a modal opens, focus should move inside it. When it closes, focus should return to the trigger element. Getting this wrong makes modal-based UIs unusable with keyboard navigation.
8. State Architecture Thinking
My React code had a pattern problem. I used useState wherever I needed data, and when things got complex, I reached for Redux. I skipped the middle.
The mental model I wish I had earlier:
- Most "global state" is actually URL state or server state. React Query / TanStack Query handles server state better than any Redux setup I've seen.
- Derived state is not stored state. If you calculate a value from existing state, compute it during render — don't store it in a second
useState. I used to sync twouseStatevalues withuseEffect, which caused dozens of subtle bugs. - Local state should stay local. Lifting state too high makes components coupled in ways that are hard to reason about and test.
9. CSS Has Architecture, Not Just Rules
I thought I knew CSS. I could build any layout you showed me.
What I didn't understand:
- Specificity wars happen because CSS isn't organized — not because CSS is hard. Systems like BEM or utility-first CSS exist to prevent them.
- Stacking contexts: The reason
z-index: 9999"doesn't work" is almost always that the element is inside a stacking context with a lower z-index than a sibling. I spent hours debugging this before understanding it. - CSS Custom Properties for theming:
var(--color-accent)isn't just convenient — it's how you build a proper theming system. My portfolio's three themes (Cyberpunk, Ignite, Boreal) all work off the same component tree because of CSS variables.
What I'd Tell My Past Self
If I could go back to the beginning of my interview preparation, here's the order I'd study:
- How the browser renders a page — everything else builds on this
- The Event Loop and JavaScript engine internals — it makes async code make sense
- HTTP deeply — request lifecycle, caching, CORS, status codes
- Web security — XSS, CSRF, CSP — even a surface-level understanding puts you ahead of 80% of freshers
- Core Web Vitals and performance — because every product company cares about this
- Accessibility fundamentals — it differentiates you immediately
But they are exactly what separates developers who can build things from developers who can build things that work — reliably, securely, and for everyone.
Every interview I passed after understanding these concepts, I passed not because I had the perfect answer, but because I could reason about the problem. I could say "it depends on the caching strategy" instead of "I'd use localStorage." That nuance is everything.
The good news? This stuff is learnable. Deeply, thoroughly learnable. It just requires studying the platform you've been building on all along — the web itself.
Take your time with it. The interviews will wait.
Building something interesting? Let's talk — I'm always up for a good engineering discussion.
What I Learned Shipping a Real Freelance Project (Maharani Food Plaza)
Next PostBuilding a High-Performance Next.js Portfolio
Enjoyed this post? Let's connect and talk frontend!
Get in Touch