Start typing in the box. Keep typing, and hit the red button. Then try the same thing with the green button.
this spinner is pure CSS — if it freezes, the main thread is blocked
// 🧊 BLOCKING — one 600ms task. Browser cannot paint. Cannot accept input. function applyCouponBad() { calculateDiscount(everything); // ~600ms of work, all at once showResult(); } // 🌊 YIELDING — same 600ms of work, chopped into 6 pieces. // After each piece we hand the mic back so the browser can breathe. async function applyCouponGood() { showSpinner(); // instant feedback, ~0ms for (const piece of split(everything, 6)) { calculateDiscount(piece); // ~100ms await new Promise(r => setTimeout(r, 0)); // 👈 the whole fix } showResult(); }
useMemo (don't redo work),
useDeferredValue / startTransition (mark work as
low-priority), a Web Worker (move work off the main thread entirely), or —
most often and most boringly — asking the backend to do it.