Lab / Open methodology
Frontend optimization: a 50,000-invoice list
50,000 invoices filtered and listed: 1.39 s → 16.5 ms. Synthetic lab; median of 10 runs. Open code and raw data.
Render every matching rowtoRender the visible window
Web arayüzü / Web UI LAB MEASUREMENT
50,000 invoices. Render the rows the screen needs.
Filter overdue invoices. Identical records and scrollable range; a different number of rows rendered at once.
The finance team spends less time waiting for a large list to respond. Keep the complete result set and render the visible section.
Render every matching row
A separate DOM row for every match.
- Invoice rows in the DOM
- 33,333
Render the visible window
Complete result list; a 40-row viewport window.
- Invoice rows in the DOM
- 40
Bars start at zero and share the same time scale across implementations.
Replace one DOM row per match with a 40-row viewport window. The same filter still examines every record; scrolling updates the window.
All load points and measurements
| Implementation | Median duration | Invoice rows in the DOM |
|---|---|---|
| Render every matching row | 29.4 ms | 666 |
| Render the visible window | 16.6 ms | 40 |
| Implementation | Median duration | Invoice rows in the DOM |
|---|---|---|
| Render every matching row | 244.9 ms | 6,666 |
| Render the visible window | 16.55 ms | 40 |
| Implementation | Median duration | Invoice rows in the DOM |
|---|---|---|
| Render every matching row | 1.386 s | 33,333 |
| Render the visible window | 16.5 ms | 40 |
Customer names stay text.
Customer 42
BeforeText preserved
✓ AfterText preserved; no HTML element created
A & B
BeforeText preserved
✓ AfterText preserved; no HTML element created
North < East > West
BeforeText preserved
✓ AfterText preserved; no HTML element created
Quote " and apostrophe '
BeforeText preserved
✓ AfterText preserved; no HTML element created
<b data-probe>Customer 42</b>
BeforeHTML element created
✓ AfterText preserved; no HTML element created
<span title="synthetic">Invoice</span>
BeforeHTML element created
✓ AfterText preserved; no HTML element created
Try it yourself
Replay the recorded lab results side by side.
As the workload grows
Duration by workload
- Before
- After
Duration by workload (ms)
Show as a table
| Source invoice records | Before | After |
|---|---|---|
| 1,000 | 29.4 ms | 16.6 ms |
| 10,000 | 244.9 ms | 16.55 ms |
| 50,000 | 1,385.8 ms | 16.5 ms |
How we measured
Environment, protocol and technical analysis
Environment and data
- Environment
- Chrome 154 · macOS · 8 logical cores · viewport 1280 × 720
- Dataset
- 1,000 / 10,000 / 50,000 synthetic invoices; same overdue filter and complete result checksum.
- Tools
- performance.now · requestAnimationFrame · DOM / scroll checks · Python independent result oracle
- Repetitions
- 3 sizes × 2 implementations × 10 recorded runs + 12 warmups; every run retained.
50,000 invoices. Render the rows the screen needs.
Filter overdue invoices. Identical records and scrollable range; a different number of rows rendered at once.
Alternating implementations in a visible browser tab. Two warmups followed by 10 runs per implementation and size. Verify the complete matching result checksum, top/bottom viewport and scroll height. Timing starts before filtering and includes DOM, layout and two requestAnimationFrame callbacks; it does not instrument physical screen presentation. Primary point: 50,000 source invoices.
Inspect the measurement script ↗What changes for the business?
The finance team spends less time waiting for a large list to respond. Keep the complete result set and render the visible section.
Change and scope
Replace one DOM row per match with a 40-row viewport window. The same filter still examines every record; scrolling updates the window.
Synthetic invoices; Chrome 154 on macOS at 1280 × 720. Measures filtering, DOM update, layout and two animation-frame callbacks. Excludes network, database and field INP.
Rendering fewer rows still examines all the data
33,333 of the 50,000 invoices match the filter. Both implementations find the complete set. The updated screen keeps only 40 DOM rows and also verifies scrolling to the bottom. The slowest modern run, 112.7 ms, remains in the raw evidence.
The text and HTML boundary
All six harmless encoding checks preserved input as text with textContent. The old HTML concatenation created elements for two inputs. This tests data rendering, not every XSS vector or the security of an entire application.
Where to start in your system
Identify the slow operation, data volume and peak workload. Establish its baseline, change the code and access pattern, then compare the same result.
What we did
Business rule and data
AIPrepared the synthetic workflow, tests and measurement automation.
VerificationPublished code and raw outputs are available for review; this is not a client project.
Implementation change
AIReplace one DOM row per match with a 40-row viewport window. The same filter still examines every record; scrolling updates the window.
VerificationOutput equivalence was independently checked; every repetition is retained.