From 0efb9cb85338c43b7f941312f2d508ea46ec9073 Mon Sep 17 00:00:00 2001 From: Ferdinand Urban Date: Wed, 3 Jun 2026 12:54:41 +0000 Subject: [PATCH] perf(state/assets): debounce saveState, defer SheetJS script (#11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - saveState is now debounced (~400ms) to coalesce rapid changes; a pending write is flushed on beforeunload and on visibilitychange→hidden so the last change is never lost. - The SheetJS +
diff --git a/js/app.js b/js/app.js index 3c10656..e5b1ca3 100644 --- a/js/app.js +++ b/js/app.js @@ -30,9 +30,11 @@ try { // Corrupt storage — start fresh } -// Call after any state mutation to persist automatically +// Persist immediately. Used by the debounced saveState and the flush handlers. let storageWarned = false; -export function saveState() { +let saveTimer = null; +function writeState() { + if (saveTimer !== null) { clearTimeout(saveTimer); saveTimer = null; } try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ employees: state.employees, @@ -52,6 +54,19 @@ export function saveState() { } } +// Call after any state mutation. Debounced to coalesce rapid changes; a pending +// write is flushed on page hide/unload so the last change is never lost. +export function saveState() { + if (saveTimer !== null) clearTimeout(saveTimer); + saveTimer = setTimeout(writeState, 400); +} + +const flushPending = () => { if (saveTimer !== null) writeState(); }; +window.addEventListener('beforeunload', flushPending); +document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') flushPending(); +}); + // Tab switching document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', () => {