Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
Run results for:
interactionObserver vs Scroll Listener
Go to the benchmark
Embed
Embed Benchmark Result
Run details:
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:
Chrome 146
Operating system:
Mac OS X 10.15.7
Device Platform:
Desktop
Date tested:
one month ago
Test name
Executions per second
ScrollListener
12446.2 Ops/sec
IntersectionObserver
7882.3 Ops/sec
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();