Performance & best practices
Write clean, fast code: immutability, avoiding layout thrashing, debouncing, linting and security basics.
You've learned the language, the browser and asynchronous code. This final lesson is about writing JavaScript like a professional: code that's readable and maintainable first, fast where it matters, and secure. These are the habits code reviewers look for.
Part 1: Readable, maintainable code#
Name things well
- Variables are nouns (
cartTotal), functions are verbs (calculateTotal), booleans are questions (isLoading,hasAccess). - Replace "magic numbers" with named constants.
- Comments explain why, not what — the code shows what.
Small functions, early returns
Prefer const, immutability and pure functions
Pure functions (same input → same output, no side effects) are trivial to test and safe to reuse. Keep side effects — DOM updates, network calls, storage — at the edges of your program.
Let tools enforce consistency
- Prettier formats code automatically — no more arguments about semicolons or quotes.
- ESLint (or the faster Oxlint/Biome) catches bugs: unused variables, missing
await, accidental globals,==comparisons. - TypeScript catches type errors before runtime.
- Tests (Node's test runner, Vitest) prove your code works and keep it working.
- Run them all in CI (e.g. GitHub Actions) on every pull request.
Handle errors deliberately
- Validate inputs at the boundaries (forms, API responses).
- Throw
Errorobjects with useful messages; never swallow errors silently. - Show users a friendly message, and log details for developers.
Part 2: Performance#
"Premature optimisation is the root of all evil." — Donald Knuth. Write clear code first, measure, then optimise the part that's actually slow.
Measure first
In the browser, the Performance panel records exactly where time goes — scripting, layout, painting — and Lighthouse audits load performance. Watch the Core Web Vitals: LCP (how fast the main content appears), INP (how quickly the page responds to input) and CLS (how much the layout jumps).
Choose the right data structure
The biggest wins usually come from algorithms, not micro-tweaks:
(Timings vary by machine, but the gap is always dramatic.) Use Map/Set for lookups, and avoid nested loops over large arrays.
Don't block the main thread
- Break long tasks into chunks and yield between them (see The event loop).
- Move heavy computation (image processing, parsing big files) to a Web Worker:
Efficient DOM updates
DOM operations are much slower than plain JavaScript. The biggest trap is layout thrashing: interleaving writes and layout reads.
More DOM tips:
- Build many elements in a
DocumentFragmentor usereplaceChildrenonce, instead of inserting one by one. - Toggle a CSS class rather than setting many inline styles.
- Animate
transformandopacity(GPU-friendly), nottop/left/width. - Use
requestAnimationFramefor visual updates. - Use event delegation instead of thousands of listeners.
- For very long lists, render only the visible rows ("virtualisation").
- Use
IntersectionObserverfor lazy-loading and "infinite scroll" instead ofscrollhandlers.
Debounce and throttle busy events
- Debounce: run once, after the events stop (search boxes, auto-save, resize end).
- Throttle: run at most once per interval while events continue (scroll position, drag, analytics).
Memoise expensive pure functions
Only memoise pure functions, and remember the cache uses memory.
Load less JavaScript
The fastest code is code you don't ship:
- Use
type="module"scripts ordeferso scripts don't block rendering. - Code-split with dynamic
import()so users download features only when needed. - Check bundle size (e.g.
npx vite-bundle-visualizer) and prefer small, tree-shakeable libraries — often the platform already does it (fetchinstead of an HTTP library,Intlinstead of a date-formatting library,structuredCloneinstead of a deep-clone package). - Compress (gzip/Brotli), cache with long-lived headers, and lazy-load images with
loading="lazy".
Avoid memory leaks
Long-running pages (single-page apps) leak memory when references stay alive:
- Remove event listeners and clear intervals when a component or widget goes away (an
AbortControllermakes this easy). - Don't keep growing global arrays or caches without limits.
- Use
WeakMapfor data attached to objects you don't own. - Use the DevTools Memory panel to compare heap snapshots.
Part 3: Security basics#
- Never insert untrusted data with
innerHTML. UsetextContent, or a sanitiser such as DOMPurify if you truly need HTML. This prevents XSS. - Never use
eval()ornew Function()with user input. - Don't put secrets in front-end code — API keys in your bundle are public.
- Don't store auth tokens in
localStorage; preferHttpOnly,Secure,SameSitecookies. - Validate on the server, always — client-side validation is just UX.
- Keep dependencies updated and run
npm audit; fewer dependencies means less risk. - Use HTTPS everywhere and a Content Security Policy header to limit what scripts can run.
A checklist for every pull request#
- Clear names, small functions, no dead code or stray
console.log/debugger -
constby default,===everywhere, no mutation of shared data - Errors handled; loading and error states in the UI
- Inputs validated; no
innerHTMLwith user data - Lint, type-check and tests pass
- Measured before optimising; no obvious O(n²) on large data
- Listeners, timers and requests cleaned up
- Accessible: real buttons, labels on inputs, keyboard support
Common mistakes#
- Micro-optimising (
forvsforEach) while shipping a 2 MB bundle. - Optimising without measuring.
- Clever one-liners that nobody (including future you) can read.
- Copy-pasting code instead of extracting a function.
What's next#
🎉 Congratulations — you've completed the JavaScript course! You can now write modern JavaScript, build interactive pages, talk to APIs, use Node and npm, and add types with TypeScript. The natural next step is the React course, where you'll use everything you've learned here — especially functions, destructuring, array methods, immutability, modules and async/await — to build component-based user interfaces.
Check your understanding
Quick quiz
1.What causes "layout thrashing"?
2.What's the main difference between debouncing and throttling?
3.Before optimising code that feels slow, what should you do first?
Finished reading?
Mark this lesson complete to track your progress.