Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
interactionObserver vs Scroll Listener
(version: 3)
Comparing performance of:
ScrollListener vs IntersectionObserver
Created:
one month ago
by:
Registered User
Jump to the latest result
HTML Preparation code:
<div id="root-div" style="position:fixed;top:0;left:0;width:600px;height:800px;overflow:auto"> <svg id="tree-svg" xmlns="http://www.w3.org/2000/svg"></svg> </div> <script> const NODE_COUNT = 900; const Y_OFFSET = 56; const NODE_RADIUS = 23; window.SCREEN_RATIO = 1; window.nodes = Array.from({ length: NODE_COUNT }, (_, i) => ({ getStartingY: () => NODE_RADIUS + Y_OFFSET * i, getRadius: () => NODE_RADIUS, getDataId: () => `node-${i}`, })); window.hydrate = function(node) { /* no-op */ }; const rootDiv = document.getElementById('root-div'); const svg = document.getElementById('tree-svg'); const svgNS = 'http://www.w3.org/2000/svg'; svg.setAttribute('height', NODE_COUNT * Y_OFFSET + 'px'); window.elements = nodes.map((node, i) => { const g = document.createElementNS(svgNS, 'g'); g.setAttribute('transform', `translate(100, ${NODE_RADIUS + Y_OFFSET * i})`); svg.appendChild(g); return g; }); window.SCROLL_STEPS = Array.from({ length: 20 }, (_, i) => Math.floor(i * (NODE_COUNT * Y_OFFSET) / 20) ); </script>
Tests:
ScrollListener
const rootDiv = document.getElementById('root-div'); let pending = nodes.map(n => ({ model: n })); const scrollHandler = () => { const scrollTop = rootDiv.scrollTop; const viewportBottom = scrollTop + rootDiv.clientHeight; const margin = rootDiv.clientHeight; pending = pending.filter(({ model }) => { const scaledY = model.getStartingY() * SCREEN_RATIO; const scaledRadius = model.getRadius() * SCREEN_RATIO; if (scaledY + scaledRadius >= scrollTop - margin && scaledY - scaledRadius <= viewportBottom + margin) { hydrate(model); return false; } return true; }); }; rootDiv.addEventListener('scroll', scrollHandler, { passive: true }); for (const scrollTop of SCROLL_STEPS) { rootDiv.scrollTop = scrollTop; rootDiv.dispatchEvent(new Event('scroll')); } rootDiv.removeEventListener('scroll', scrollHandler);
IntersectionObserver
const rootDiv = document.getElementById('root-div'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { hydrate(entry.target); observer.unobserve(entry.target); } }); }, { root: rootDiv }); elements.forEach(el => observer.observe(el)); for (const scrollTop of SCROLL_STEPS) { rootDiv.scrollTop = scrollTop; void rootDiv.getBoundingClientRect(); } observer.disconnect();
Rendered benchmark preparation results:
Suite status:
<idle, ready to run>
Run tests (2)
Previous results
Fork
Test case name
Result
ScrollListener
IntersectionObserver
Fastest:
N/A
Slowest:
N/A
Latest run results:
Run details:
(Test run date:
one month ago
)
User agent:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36
Browser/OS:
Chrome 146 on Mac OS X 10.15.7
View result in a separate tab
Embed
Embed Benchmark Result
Test name
Executions per second
ScrollListener
6699.0 Ops/sec
IntersectionObserver
8215.2 Ops/sec
Related benchmarks:
creating array from array like objects
js selector options
array vs node list
contains2 vs closest2
contains2 vs closest
for loop vs Array.from Nodelist
test_html_in_javascript
Node closest vs node contains forkedd
querySelectorAll, iterated map or array map
Comments
Confirm delete:
Do you really want to delete benchmark?