JavaScript · Advanced

JavaScript Performance

Fast code starts with measuring, not guessing. A few habits make the biggest difference in real applications.

Advanced 5 min Lesson 46 of 49 Runnable examples
0/49 in JavaScript
On this page · 5 min · Advanced

Learning objectives#

  • Measure code with performance.now
  • Choose data structures for fast lookups
  • Batch DOM updates
  • Know when to debounce, lazy-load and split code

Explanation#

Measure first: performance.now() gives precise timestamps; the DevTools Performance panel shows where time really goes.

Data structures matter: Array.includes checks items one by one; Set.has jumps straight to the answer.

The DOM is slow compared to plain JavaScript. Build elements off-page (DocumentFragment or one innerHTML/replaceChildren call) and insert once.

Reading layout (offsetHeight) right after writing styles forces the browser to recalculate layout repeatedly — “layout thrashing”. Group reads, then writes.

Code example: Array.includes vs Set.has#

JavaScriptArray.includes vs Set.has Runnable
const ids = Array.from({ length: 100_000 }, (_, i) => i);
const idSet = new Set(ids);
const lookups = Array.from({ length: 2_000 }, () => Math.floor(Math.random() * 200_000));


let t = performance.now();
lookups.filter(x => ids.includes(x));
const arrayMs = performance.now() - t;


t = performance.now();
lookups.filter(x => idSet.has(x));
const setMs = performance.now() - t;


console.log(`Array.includes: ${arrayMs.toFixed(1)} ms`);
console.log(`Set.has:        ${setMs.toFixed(1)} ms`);
console.log('Set is faster:', setMs < arrayMs);
Expected output
Array.includes: 95.3 ms
Set.has:        0.4 ms
Set is faster: true

(your exact timings will differ)
Opens this example in the full playground

Step-by-step explanation#

  1. Both approaches answer the same question for 2,000 lookups.
  2. includes may scan up to 100,000 items for each lookup.
  3. Set.has finds each answer almost instantly.
  4. Measuring proves the difference instead of guessing.

Real-world use case#

Filtering thousands of products, checking permissions, and rendering long lists smoothly all depend on these habits.

Common mistakes#

Optimising without measuring

Guesses are often wrong. Profile first, then fix the slowest part.

Appending to the DOM in a loop

Thousands of separate appends trigger repeated work. Build a fragment and append once.

Best practices#

  • Measure with DevTools and performance.now
  • Use Set/Map for frequent lookups
  • Batch DOM writes and avoid layout thrashing
  • Debounce/throttle frequent events; lazy-load heavy code with dynamic import()

Remember this#

Measure → change → measure again.

Lots of lookups? Use a Set or Map.

Touch the DOM as rarely as possible — build, then insert once.

Practice exercise#

Your task: Render 1,000 <li> elements efficiently into a <ul> using a DocumentFragment.

Show solution
JavaScript Illustrative
const frag = document.createDocumentFragment();
for (let i = 1; i <= 1000; i++) {
  const li = document.createElement('li');
  li.textContent = `Item ${i}`;
  frag.append(li);
}
list.append(frag); // one DOM insertion

Mini quiz#

JavaScript Performance quizMultiple choice Question 1 of 1

What is the first step in performance tuning?

Score so far: 0/0

Want more? Practise all JavaScript MCQs · JavaScript interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.