Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Constructable styles benchmark
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Constructable styles benchmark</title>
<style>
label {
display: block;
margin: 20px 0;
}
</style>
</head>
<body>
<h1>Constructable styles benchmark</h1>
<form>
<label>
Number of components:
<input id="numComponents" type="number" value="1000">
</label>
<label>
Use constructable stylesheets
<input id="useConstruct" type="checkbox" checked>
</label>
<button id="render" type="button">Render components</button>
</form>
<pre></pre>
<script type="module">
const $ = document.querySelector.bind(document)
const $$ = _ => [...document.querySelectorAll(_)]
const useConstructCheckbox = $('#useConstruct')
const numComponentsInput = $('#numComponents')
const renderButton = $('#render')
const pre = $('pre')
const css = 'div { color: red }'
const sheet = new CSSStyleSheet()
sheet.replaceSync(css)
function createDiv() {
const div = document.createElement('div')
div.textContent = 'hello'
return div
}
customElements.define('construct-component', class extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
this.shadowRoot.adoptedStyleSheets = [sheet]
this.shadowRoot.appendChild(createDiv())
}
})
customElements.define('noconstruct-component', class extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
const style = document.createElement('style')
style.textContent = css
this.shadowRoot.appendChild(style)
this.shadowRoot.appendChild(createDiv())
}
})
renderButton.addEventListener('click', () => {
const numComponents = parseInt(numComponentsInput.value, 10) || 0
const useConstructableStyles = useConstructCheckbox.checked
const name = useConstructableStyles ? 'construct-component' : 'noconstruct-component'
performance.mark('start')
for (let i = 0; i < numComponents; i++) {
document.body.appendChild(document.createElement(name))
}
// requestPostAnimationFrame polyfill using rAF + postMessage
requestAnimationFrame(() => {
addEventListener('message', () => {
performance.measure('total', 'start')
const duration = performance.getEntriesByName('total').slice(-1)[0].duration
pre.innerText += `${duration} ms\n`
// cleanup
for (const el of $$(name)) {
el.remove()
}
}, { once: true })
postMessage('', '*')
})
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment