Skip to content

Instantly share code, notes, and snippets.

@cferdinandi
Created October 16, 2023 15:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cferdinandi/cbebe295d66c8a75d360312c910a3ffb to your computer and use it in GitHub Desktop.
Save cferdinandi/cbebe295d66c8a75d360312c910a3ffb to your computer and use it in GitHub Desktop.
Reef vs. Preact Performance Test - https://reefjs.com
<!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>
<!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