-
-
Save aehlke/bc0e23a21a19cbd0abc13cf55c3d1d91 to your computer and use it in GitHub Desktop.
Test async getBoundingClientRect with IntersectionObserver vs rAF + gBCR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<title>IntersectionObserver vs getBoundingClientRect (50,000 elements)</title> | |
<style> | |
#theContainer { width: 100vw; max-width: 100%; } | |
.test-elem { margin:1px; display:inline-block; width:10px; height:10px; background:#ddd; } | |
</style> | |
</head> | |
<body> | |
<h1>IntersectionObserver vs getBoundingClientRect (50,000 elements)</h1> | |
<button type=button onclick="testIO()">Test using IntersectionObserver</button> | |
<button type=button onclick="testGBCR()">Test using rAF + getBoundingClientRect</button> | |
<button type=button onclick="testGBCRSync()">Test using sync getBoundingClientRect</button> | |
<div id="theContainer"></div> | |
<script> | |
const N = 10000; | |
// Pre-create all elements on page load | |
function prefillContainer() { | |
let bigText = ''; | |
function rubyDigits(str) { | |
return String(str).split('').map(d => | |
`<ruby>${d}<rt>${d}</rt></ruby>` | |
).join(''); | |
} | |
for (let i = 0; i < N; i++) { | |
bigText += `<div class="test-elem" id="elem${i}">${rubyDigits(i)}</div>`; | |
} | |
document.getElementById('theContainer').innerHTML = bigText; | |
} | |
prefillContainer(); | |
function asyncGetBoundingClientRectUsingIO(element) { | |
return new Promise(function (resolve) { | |
var observer = new IntersectionObserver(function (entries) { | |
observer.disconnect(); | |
resolve(entries[0].boundingClientRect); | |
}); | |
observer.observe(element); | |
}) | |
} | |
function asyncGetBoundingClientRectUsingGBCR(element) { | |
return new Promise(function (resolve) { | |
requestAnimationFrame(function () { | |
var rect = element.getBoundingClientRect(); | |
resolve(rect); | |
}) | |
}) | |
} | |
function syncGetBoundingClientRect(element) { | |
return Promise.resolve(element.getBoundingClientRect()); | |
} | |
function Marker(str) { | |
this.str = str; | |
} | |
Marker.prototype.mark = function () { | |
performance.mark('start_' + this.str) | |
} | |
Marker.prototype.stop = function () { | |
performance.mark('end_' + this.str) | |
performance.measure(this.str, 'start_' + this.str, 'end_' + this.str) | |
return performance.getEntriesByName(this.str).reverse().slice(-1)[0].duration | |
} | |
function stringifyRect(rect) { | |
return JSON.stringify({ left: rect.left, top: rect.top, width: rect.width, height: rect.height }) | |
} | |
async function testGBCR() { | |
var marker = new Marker('gbcr-' + Math.random()) | |
marker.mark() | |
let promises = []; | |
for (let i = 0; i < N; i++) { | |
let randIdx = Math.floor(Math.random() * N); | |
let el = document.getElementById('elem' + randIdx); | |
el.style.background = '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, '0'); | |
promises.push(asyncGetBoundingClientRectUsingGBCR(el)); | |
} | |
let rects = await Promise.all(promises); | |
var duration = marker.stop(); | |
console.log('getBoundingClientRect (rAF): duration: ' + duration.toFixed(2) + 'ms, last rect: ' + stringifyRect(rects[rects.length - 1])); | |
} | |
async function testGBCRSync() { | |
var marker = new Marker('gbcrsync-' + Math.random()) | |
marker.mark() | |
let promises = []; | |
for (let i = 0; i < N; i++) { | |
let randIdx = Math.floor(Math.random() * N); | |
let el = document.getElementById('elem' + randIdx); | |
el.style.background = '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, '0'); | |
promises.push(syncGetBoundingClientRect(el)); | |
} | |
let rects = await Promise.all(promises); | |
var duration = marker.stop(); | |
console.log('getBoundingClientRect (sync): duration: ' + duration.toFixed(2) + 'ms, last rect: ' + stringifyRect(rects[rects.length - 1])); | |
} | |
async function testIO() { | |
var marker = new Marker('io-' + Math.random()) | |
marker.mark() | |
let promises = []; | |
for (let i = 0; i < N; i++) { | |
let randIdx = Math.floor(Math.random() * N); | |
let el = document.getElementById('elem' + randIdx); | |
el.style.background = '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, '0'); | |
promises.push(asyncGetBoundingClientRectUsingIO(el)); | |
} | |
let rects = await Promise.all(promises); | |
var duration = marker.stop(); | |
console.log('IntersectionObserver: duration: ' + duration.toFixed(2) + 'ms, last rect: ' + stringifyRect(rects[rects.length - 1])); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment