Expert · Performance and Node.js · topic 52 of 61 · 30 min
Performance thinking and Big-O
Explanation
Why think about growth?
Code that is instant with 100 orders can freeze with 100,000. What matters is not the time for one test run on your laptop, but how the time GROWS when the data grows. Big-O notation is a simple way to describe that growth, ignoring small details like the speed of your computer.
| Big-O | Name | Example | 10,000 items ≈ steps |
|---|---|---|---|
| O(1) | constant | arr[5], map.get(key), set.has(x) | 1 |
| O(log n) | logarithmic | binary search in a sorted array | 14 |
| O(n) | linear | one loop, includes, find, sum | 10,000 |
| O(n log n) | linearithmic | sorting with arr.sort | ~140,000 |
| O(n²) | quadratic | a loop inside a loop over the same data | 100,000,000 |
The most common slow pattern
A loop that calls includes, indexOf or find on another big array inside it is O(n × m). Converting the inner array to a Set or Map first makes each lookup O(1), so the whole thing becomes O(n + m).
// O(n × m): for each order, scan all blocked customers
const blocked = customers.filter((c) => c.blocked).map((c) => c.id);
const ok = orders.filter((o) => !blocked.includes(o.customerId));
// O(n + m): build a Set once, then each check is instant
const blockedSet = new Set(blocked);
const ok2 = orders.filter((o) => !blockedSet.has(o.customerId));Measure, do not guess
console.time('dedupe');
const unique = [...new Set(bigList)];
console.timeEnd('dedupe'); // dedupe: 3.2 ms
const t0 = performance.now(); // high-resolution timer (ms with decimals)
heavyWork();
console.log(`took ${(performance.now() - t0).toFixed(1)} ms`);Measure with realistic data sizes, run more than once (the first run includes warm-up while the engine optimises your code), and use the Performance panel in browser DevTools or node --cpu-prof to see where time really goes.
Cheap wins
- Do work once, outside loops: build Sets/Maps, compile regexes, create Intl formatters before the loop.
- Avoid repeated string building in huge loops; collect parts in an array and join once.
- Stop early: use find/some instead of filter(...)[0] or filter(...).length > 0.
- Avoid unnecessary copies of big arrays in hot loops.
- Paginate: do not load or render 50,000 rows at once.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Performance thinking and Big-O · 1/6
In this lesson you will learn to think about how code slows down as data grows.
Prefer a video by a teacher? Find free videos on “big o notation javascript explained time complexity” on YouTube ↗
In real life: A slow report that took 40 minutes
A logistics firm's nightly report matched 200,000 shipments against 50,000 invoices with find inside a loop. It took 40 minutes and sometimes timed out. Building a Map of invoices by shipment id first made the matching take under a second.
const invoices = [{ shipId: 'S1', amt: 900 }, { shipId: 'S2', amt: 450 }];
const shipments = [{ id: 'S2' }, { id: 'S1' }, { id: 'S3' }];
const byShip = new Map(invoices.map((inv) => [inv.shipId, inv]));
console.log(shipments.map((s) => byShip.get(s.id)?.amt ?? 'missing')); // [450, 900, 'missing']Practice (0/2 done)
hasDuplicate(list) currently compares every pair (O(n²)). Rewrite it in O(n) using a Set. The test uses a list of 60,000 numbers.
Write missingInvoices(shipments, invoices) that returns the ids of shipments with no invoice (invoice.shipId === shipment.id), in shipment order, in O(n + m).
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Memory and garbage collectionPerformance and Node.js · same module
- Node.js basicsPerformance and Node.js · same module
- Files and a tiny server in NodePerformance and Node.js · same module
- Big-O and searchingPython Programming · Algorithms, data structures and testing
- Big-O time complexityData Structures and Algorithms (DSA) for interviews · Thinking in Big-O
- Making the Notes app fastFull-Stack Development · Performance, security and testing
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is the Big-O of set.has(x)?
Answer: O(1) on average
Sets use hashing for near-constant-time lookups.
A loop over n items that calls array.includes on another n items is…
Answer: O(n²)
includes is itself a loop, so the total is n × n.
What should you do before optimising?
Answer: Measure where time is really spent
Measurement shows the real bottleneck.
Binary search on 1,000,000 sorted items needs about how many steps?
Answer: 20
log2 of a million is about 20.
About how many steps does binary search need for 1,000,000 sorted items?Related
Answer: About 20
Halving 1,000,000 about 20 times gets down to 1, because 2 to the power 20 is about a million.
From Big-O and searching
Code takes 4n² + 10n + 7 steps. What is its Big-O?Related
Why test your app with "Slow 4G" and CPU slowdown in DevTools?Related
Answer: Many real users are on budget phones and patchy mobile networks
Your laptop on Wi-Fi hides problems that users on cheap phones and mobile data feel every day.
Why prefer "".join(parts) over s += part in a long loop?Related
Answer: s += part may copy the whole growing string each time, O(n²) in total
Strings are immutable, so += can create a new string every time; join builds the result once.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Performance and Node.js” before its exam: Memory and garbage collection, Node.js basics, Files and a tiny server in Node, Real project tooling.
- Module 11 exam: Performance and Node.js · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Interview preparation and career. 61 topics left in the course before the final exam.