Created
October 16, 2023 15:40
-
-
Save cferdinandi/cbebe295d66c8a75d360312c910a3ffb to your computer and use it in GitHub Desktop.
Reef vs. Preact Performance Test - https://reefjs.com
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> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Preact</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
</head> | |
<body> | |
<div id="app"></div> | |
<script type="module"> | |
import {html, render, signal} from "https://cdn.jsdelivr.net/npm/preact-htm-signals-standalone/dist/standalone.js"; | |
// Start | |
let start = performance.now(); | |
// Create a signal | |
let rows = signal([]); | |
/** | |
* Add rows to the table | |
*/ | |
function addRows () { | |
for (let i = 0; i < 1000; i++) { | |
rows.value = [...rows.value, { | |
col1: crypto.randomUUID(), | |
col2: crypto.randomUUID(), | |
col3: crypto.randomUUID() | |
}]; | |
} | |
} | |
/** | |
* Move rows around to force diffing | |
*/ | |
function swapRows () { | |
let copy = Array.from(rows.value); | |
let cloned = copy.slice(500, 1500); | |
copy.splice(500, 1000, ...cloned); | |
rows.value = copy; | |
} | |
/** | |
* Delete rows to force a render | |
*/ | |
function deleteRows () { | |
let copy = Array.from(rows.value); | |
copy.splice(125, 250); | |
rows.value = copy; | |
} | |
/** | |
* Add a delay to avoid batched rendering | |
* @param {Function} fn The function to run | |
* @return {Promise} A Promise that resolves after it runs | |
*/ | |
function delay (fn) { | |
return new Promise(function (resolve) { | |
setTimeout(function () { | |
fn(); | |
resolve(); | |
}, 500); | |
}); | |
} | |
/** | |
* The UI HTML template | |
* @return {Function} The Preact template function | |
*/ | |
function App () { | |
return html` | |
<table> | |
<thead> | |
<tr> | |
<th>First Name</th> | |
<th>Last Name</th> | |
<th>Super Hero</th> | |
</tr> | |
</thead> | |
<tbody> | |
${rows.value.map(function (row) { | |
return html`<tr key="${row.col1} ${row.col2} ${row.col3}"> | |
<td key="${row.col1}">${row.col1}</td> | |
<td key="${row.col2}">${row.col2}</td> | |
<td key="${row.col3}">${row.col3}</td> | |
</tr>`; | |
})} | |
</tbody> | |
</table>`; | |
} | |
// Create a reactive component | |
render(html`<${App}/>`, document.querySelector('#app')); | |
// With no delay (will batch render) | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// swapRows(); | |
// deleteRows(); | |
// deleteRows(); | |
// addRows(); | |
// swapRows(); | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// swapRows(); | |
// deleteRows(); | |
// deleteRows(); | |
// addRows(); | |
// swapRows(); | |
// With a delay to trigger multiple renders | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(swapRows); | |
await delay(deleteRows); | |
await delay(deleteRows); | |
await delay(addRows); | |
await delay(swapRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(swapRows); | |
await delay(deleteRows); | |
await delay(deleteRows); | |
await delay(addRows); | |
await delay(swapRows); | |
// End | |
let end = performance.now(); | |
console.log(`Perf: ${end - start}ms - ${(end - start) / 1000}s`); | |
</script> | |
</body> | |
</html> |
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> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Reef</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
</head> | |
<body> | |
<div id="app"></div> | |
<script type="module"> | |
import {signal, component} from 'https://cdn.jsdelivr.net/npm/reefjs@13/dist/reef.es.min.js'; | |
// Start | |
let start = performance.now(); | |
// Create a signal | |
let rows = signal([]); | |
/** | |
* Add rows to the table | |
*/ | |
function addRows () { | |
for (let i = 0; i < 1000; i++) { | |
rows.push({ | |
col1: crypto.randomUUID(), | |
col2: crypto.randomUUID(), | |
col3: crypto.randomUUID() | |
}); | |
} | |
} | |
/** | |
* Move rows around to force diffing | |
*/ | |
function swapRows () { | |
let cloned = rows.slice(500, 1500); | |
rows.splice(500, 1000, ...cloned); | |
} | |
/** | |
* Delete rows to force a render | |
*/ | |
function deleteRows () { | |
rows.splice(125, 250); | |
} | |
/** | |
* Add a delay to avoid batched rendering | |
* @param {Function} fn The function to run | |
* @return {Promise} A Promise that resolves after it runs | |
*/ | |
function delay (fn) { | |
return new Promise(function (resolve) { | |
setTimeout(function () { | |
fn(); | |
resolve(); | |
}, 500); | |
}); | |
} | |
/** | |
* The UI HTML template | |
* @return {String} The HTML string | |
*/ | |
function template () { | |
return ` | |
<table> | |
<thead> | |
<tr> | |
<th>First Name</th> | |
<th>Last Name</th> | |
<th>Super Hero</th> | |
</tr> | |
</thead> | |
<tbody> | |
${rows.map(function (row) { | |
return `<tr key="${row.col1} ${row.col2} ${row.col3}"> | |
<td key="${row.col1}">${row.col1}</td> | |
<td key="${row.col2}">${row.col2}</td> | |
<td key="${row.col3}">${row.col3}</td> | |
</tr>`; | |
}).join('')} | |
</tbody> | |
</table>`; | |
} | |
// Create a reactive component | |
component('#app', template); | |
// With no delay (will batch render) | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// swapRows(); | |
// deleteRows(); | |
// deleteRows(); | |
// addRows(); | |
// swapRows(); | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// addRows(); | |
// swapRows(); | |
// deleteRows(); | |
// deleteRows(); | |
// addRows(); | |
// swapRows(); | |
// With a delay to trigger multiple renders | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(swapRows); | |
await delay(deleteRows); | |
await delay(deleteRows); | |
await delay(addRows); | |
await delay(swapRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(addRows); | |
await delay(swapRows); | |
await delay(deleteRows); | |
await delay(deleteRows); | |
await delay(addRows); | |
await delay(swapRows); | |
// End | |
let end = performance.now(); | |
console.log(`Perf: ${end - start}ms - ${(end - start) / 1000}s`); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment