Created
December 3, 2023 03:39
-
-
Save thomaswilburn/dbb41b931df03f243f23d0f4a3b0f69e to your computer and use it in GitHub Desktop.
Benchmark Lit iteration vs. replaceChildren
This file contains 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> | |
<ul id="ul"></ul> | |
<script type="module"> | |
import { html, render } from "https://unpkg.com/lit-html"; | |
import { repeat } from "https://unpkg.com/lit-html/directives/repeat.js"; | |
import { map } from "https://unpkg.com/lit-html/directives/map.js"; | |
function replacer(container, data, factory, update = () => {}) { | |
} | |
var guid = 0; | |
function mutate(list) { | |
var pick = () => Math.floor(Math.random() * list.length); | |
// add 100 items | |
for (var i = 0; i < 100; i++) { | |
list.splice(pick(), 0, { key: ++guid }); | |
} | |
// remove 100 items | |
for (var i = 0; i < 100; i++) { | |
list.splice(pick(), 1); | |
} | |
// shuffle 100 items | |
for (var i = 0; i < 100; i++) { | |
var a = pick(); | |
var b = pick(); | |
var swap = list[a]; | |
list[a] = list[b]; | |
list[b] = swap; | |
} | |
} | |
class Replacer { | |
mapping = new WeakMap(); | |
constructor(container, factory = () => document.createElement("li")) { | |
this.container = container; | |
this.factory = factory; | |
} | |
sync(data, update = () => {}) { | |
var elements = data.map(d => { | |
var e = this.mapping.get(d); | |
if (!e) { | |
e = this.factory(d); | |
this.mapping.set(d, e); | |
} | |
update(d, e); | |
return e; | |
}); | |
this.container.replaceChildren(...elements); | |
} | |
} | |
var tick = () => new Promise(ok => requestAnimationFrame(ok)); | |
async function testLit() { | |
ul.innerHTML = ""; | |
var template = data => html`${repeat(data, d => d.key, d => html`<li> Item: ${d.key}`)}`; | |
// var template = data => html`${map(data, d => html`<li> Item: ${d.key}`)}`; | |
var data = []; | |
for (var i = 0; i < 1000; i++) { | |
data.push({ key: ++guid }); | |
} | |
var times = []; | |
// initial render | |
render(template(data), ul); | |
for (var i = 0; i < 100; i++) { | |
mutate(data); | |
var start = performance.now(); | |
render(template(data), ul); | |
var elapsed = performance.now() - start; | |
times.push(elapsed); | |
await tick(); | |
} | |
var avg = times.reduce((t, i) => t + i, 0) / times.length; | |
console.log("Lit time:", avg); | |
var min = Math.min(...times); | |
var max = Math.max(...times); | |
console.log(`Minimum: ${min}, Maximum: ${max}`) | |
} | |
async function testReplace() { | |
ul.innerHTML = ""; | |
var factory = d => { | |
var li = document.createElement("li"); | |
li.innerHTML = `Item: ${d.key}`; | |
return li; | |
} | |
var binding = new Replacer(ul, factory); | |
var data = []; | |
for (var i = 0; i < 1000; i++) { | |
data.push({ key: ++guid }); | |
} | |
var times = []; | |
// initial render | |
binding.sync(data); | |
for (var i = 0; i < 100; i++) { | |
mutate(data); | |
var start = performance.now(); | |
binding.sync(data); | |
var elapsed = performance.now() - start; | |
times.push(elapsed); | |
await tick(); | |
} | |
var avg = times.reduce((t, i) => t + i, 0) / times.length; | |
console.log("replaceChildren time:", avg); | |
var min = Math.min(...times); | |
var max = Math.max(...times); | |
console.log(`Minimum: ${min}, Maximum: ${max}`) | |
} | |
await testLit(); | |
await testReplace(); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment