Things Your Browser Does Behind Your Back
Unknown quirks with the browser.

Just a guy who loves to write code and watch anime.
The Six Connection Limit
Browsers limit how many requests they send to the same domain at the same time. For HTTP/1.1 it is usually six. If your page fires off thirty requests at once the browser queues them. Six go out. The rest wait.
I ran into this on a project back in the days where a page needed to fetch data per item on the client. 😅
Some items just would not load and I could not figure out why. Turns out the requests were queuing and timing out. The real fix was not fighting the limit. The architecture was wrong. I moved the per-item data to the server and returned it all together with the items in one response.
If you are making a lot of parallel requests from the client you are probably doing something wrong one level up.
fetch Does Not Fail Like You Think
fetch does not reject on a 404. Or a 500. Or any HTTP error. It only rejects on network failures. Like the server is unreachable or DNS fails.
A 500 response is still a successful fetch as far as the browser is concerned. You got bytes back. If you are not checking response.ok you are silently swallowing errors.
localStorage Blocks the Main Thread
localStorage is synchronous. Every read and write blocks. It is not async. There is no callback. No promise. It just stops everything until the operation is done.
On a fast machine with a small store you will never notice. But if you are storing a lot of data or reading from it frequently it can cause jank. Especially on lower end devices. It’s generally never an issue, but good to be aware of.
Background Tabs Get Throttled
When a user switches to another tab the browser starts throttling your timers. setTimeout and setInterval get clamped to once per second at best. Some browsers throttle even harder after a few minutes. This is an issue I dealt with at Lovable where I couldn’t figure out why setTimeout wasn’t running when going to a different tab.
requestAnimationFrame just stops entirely.
If you are relying on precise timing for something in a background tab it will not work. WebSocket connections stay alive but your polling logic and animation loops basically freeze.
The 4ms Timer Clamp
Even in a foreground tab setTimeout(fn, 0) is not actually zero. After about four or five nested calls the browser clamps the minimum delay to 4ms. This is in the spec.
If you are using nested timeouts for some kind of tight loop you will hit a hard floor. It will never go faster than 4ms per tick. For truly fast async work use MessageChannel or queueMicrotask instead.
z-index Is Not What You Think
You set z-index: 9999 and the element is still behind something else. Everyone has been there.
z-index only works within a stacking context. Certain CSS properties create new stacking contexts. transform. opacity less than 1. filter. will-change. position: fixed.
Once an element creates a new stacking context its children can never escape it. Your z-index: 9999 only competes with siblings inside that same context. The parent itself might have a z-index of 1 and lose to something else entirely.
The Back-Forward Cache Will Break Your Assumptions
Modern browsers cache entire pages in memory when you navigate away. Hit the back button and the page is restored instantly. No reload. No re-render. JavaScript state is frozen and resumed.
This is called bfcache. It is great for performance. It also means your page load event listeners do not fire again. If you are setting up state in load or cleaning up in beforeunload things get weird.
Open WebSocket connections and unfinished fetch requests can prevent bfcache from working at all. Use the pageshow and pagehide events instead if you need to handle this correctly.
CSS Transitions Have a Cost You Cannot See
Animating width or height or top or margin forces the browser to recalculate layout. Every frame. That means it has to figure out where every other element on the page goes. Every frame.
Animating transform and opacity does not trigger layout. These properties get composited on the GPU. The browser barely breaks a sweat.
If your animations feel janky you are probably animating the wrong properties. Move things with transform: translateX() instead of left. Scale things with transform: scale() instead of changing width.






