JavaScript performance benchmarking is the antidote to optimization folklore. Before replacing every reduce() with a classic for loop or hand-writing a sort algorithm, measure the workload your users actually create.
That is the useful lesson in the original video: different JavaScript techniques can produce dramatically different results under a benchmark, but the result is not a universal ranking. The real win is adopting a repeatable process for discovering where performance matters—and leaving readable, reliable code alone everywhere else.
The rule that matters: measure, then optimize
The video is framed around Rob Pike’s programming rules, especially the advice to avoid tuning for speed until measurement proves that one area dominates runtime. That principle remains a practical guardrail for teams working on web apps, APIs, data pipelines, and AI-enabled products: a bottleneck is often somewhere less glamorous than the code being debated in a pull request.
A slow product may be waiting on an API, parsing oversized JSON, rendering too much UI, repeatedly querying a database, or doing unnecessary work on every request. Rewriting a short array callback in that situation produces a nicer benchmark while doing almost nothing for the user.
This is why performance work should begin with a concrete question. For example: “Does filtering this 500,000-row export delay a request?” is testable. “Are functional methods slow?” is too broad to lead to a useful engineering decision.
The original video makes this distinction well by benchmarking loops, membership checks, and sorting separately. Its value is less about declaring a universal winner than showing developers how quickly intuition can be replaced with evidence. Rob Pike’s second rule is blunt for a reason: don’t tune unless the measured cost is large enough to outweigh the added complexity. (cs.unc.edu)
How JavaScript performance benchmarking works with Deno
Deno offers a built-in benchmark runner: register cases with Deno.bench() and execute them with deno bench. The output includes average time per iteration, iterations per second, a range, and percentile figures; grouped tests can also be compared against a named baseline. That makes it a lightweight option for JavaScript or TypeScript projects that want reproducible microbenchmarks without adding a separate library. (docs.deno.com)
A benchmark should compare equivalent work. If one version creates test data inside the measured function while the other receives precomputed data, the result primarily measures allocation and setup—not the operation you intended to study. Deno explicitly supports marking a critical section so setup and teardown can be excluded when appropriate. (docs.deno.com)
A credible benchmark also needs to reflect production conditions:
- Use representative data sizes. A loop over 50 items can behave very differently from one over a million.
- Test realistic data shapes. Numbers, strings, objects, duplicates, sorted inputs, and random inputs can all change results.
- Include construction costs. If a
Setis created only to make one lookup, measure creation plus lookup—not justhas(). - Run multiple times. Treat a tiny difference as noise until repeated runs show a meaningful, stable gap.
- Benchmark the target runtime. A Deno result is informative for Deno, but it is not automatically a Node.js or browser result.
For application-level decisions, pair a microbenchmark with profiling and user-facing metrics. A function that is twice as fast but accounts for 0.1% of request time is not necessarily worth making harder to read.
Loops: a classic for loop can win, but context decides
The video’s loop test compares forEach(), reduce(), for...of, and an index-based for loop while summing large arrays. Its reported result is familiar: a traditional indexed loop can outperform more declarative styles when the array is enormous and the loop body is extremely small.
That outcome makes sense as a benchmark scenario. Callback-based array methods invoke a function for each element, while for...of uses iteration semantics; an indexed loop can give an engine a simpler hot path. But it is a mistake to translate that observation into a blanket style rule.
For normal UI lists, modest API payloads, and one-off transformations, map(), filter(), reduce(), and for...of are usually clearer and plenty fast. Modern JavaScript engines also optimize aggressively, so the exact ordering can shift by engine version, input type, surrounding code, and whether the engine has warmed up. MDN cautions that JavaScript engine behavior is runtime-specific even though the language semantics are standardized. (developer.mozilla.org)
The practical rule is straightforward: use expressive array methods by default. Switch to a lower-level loop only after profiling or a realistic benchmark shows that a hot, high-volume loop is a material cost.
The data-structure lesson: when a Set beats includes()
The most actionable example in the source is membership testing. Array.prototype.includes() examines array entries until it finds a match or reaches the end. If an application repeatedly checks whether values from one large collection exist in another, that repeated scanning can turn into expensive work.
Converting the lookup collection to a Set changes the shape of the task. Set.prototype.has() checks membership using an implementation designed for sublinear average access time; MDN specifically notes that has() is, on average, faster than Array.prototype.includes() when the collection sizes are comparable. (developer.mozilla.org)
That does not mean “always replace arrays with Sets.” A Set enforces unique values, has memory and construction costs, and does not preserve the same indexing and serialization behavior developers may expect from an array. The appropriate question is whether the collection is reused for enough lookups to repay the conversion cost.
A good decision framework is:
- Keep an array when order, duplicates, positional access, or a small number of lookups matters most.
- Build a
Setwhen the same large collection is consulted repeatedly for membership. - Measure the full workflow, including
new Set(values), rather than isolating a singlehas()call. - Use a
Mapinstead when each key needs associated data rather than a yes-or-no membership answer.
This is also where Pike’s later rules become relevant: choosing an appropriate data structure usually matters more than chasing tiny syntactic differences.
Why custom sorting is usually the wrong optimization
The video also tests custom sorting implementations against Array.prototype.sort(), finding that a quicksort implementation can win for a particular numeric dataset while bubble sort performs poorly. The important qualifier is “particular.” Sorting performance depends heavily on input size, input distribution, comparator cost, allocation behavior, and the runtime’s implementation.
Built-in Array.prototype.sort() deserves a strong default presumption. Its implementation is maintained and optimized by the runtime, and modern ECMAScript requires sort stability, an important correctness property that homegrown algorithms can easily overlook. (tc39.es)
A custom sorter may be justified in a proven hot path with constrained data and a documented benchmark advantage. Even then, engineering teams should weigh maintenance, testing, edge cases, and correctness against the speedup. A sorting routine that saves milliseconds but introduces subtle ordering bugs is not an optimization.
Conclusion: optimize the work that users can feel
JavaScript performance benchmarking is not a contest to find the fastest loop. It is a discipline for identifying expensive work, validating a change, and stopping once the user-visible problem is solved.
The source video’s experiments offer useful instincts: index-based loops can matter at large scale, Set is often the better tool for repeated membership checks, and native methods are frequently good enough. The broader lesson is more durable: write the simple version first, collect evidence from realistic workloads, then make the smallest optimization that removes a real bottleneck.
For creators and product teams, that approach protects both speed and delivery. It keeps engineers from polishing microseconds while users wait on seconds—and it makes the optimizations that do ship easier to explain, maintain, and trust.