feat: implement Web Worker architecture for efficient data sync

- Add data-sync.worker.js: separate thread for API calls (30s interval)
- Add app.js: main thread with DOM update logic and localStorage integration
- Update index.html: remove inline scripts, use external app.js
- Implement granular DOM updates (only update changed elements)
- Add localStorage persistence for health and models data
- Add Web Worker fallback for unsupported browsers
- Add WEB_WORKERS.md documentation with architecture details

Benefits:
- Main thread never blocked by network requests
- UI stays responsive at 60 FPS
- Offline support via localStorage
- Efficient DOM updates (no unnecessary re-renders)
- Better browser support and performance
This commit is contained in:
Luca Sacchi Ricciardi
2026-04-24 19:16:51 +02:00
parent 4b782ffdc8
commit 9a6f835ddf
4 changed files with 516 additions and 124 deletions
+90
View File
@@ -0,0 +1,90 @@
/**
* LLM Monitor - Data Sync Worker
* Aggiorna i dati in background e notifica il main thread
*/
const API_BASE = "/api/v1";
const REFRESH_INTERVAL = 30000; // 30 secondi
// Formattare bytes
function formatBytes(bytes) {
if (bytes === 0) return "0 B";
const k = 1024;
const sizes = ["B", "KB", "MB", "GB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toFixed(2) + " " + sizes[i];
}
// Recuperare health
async function fetchHealth() {
try {
const response = await fetch(`${API_BASE}/health`);
if (response.ok) {
const data = await response.json();
return {
status: data.status,
ollama_status: data.ollama_status,
timestamp: new Date().toISOString()
};
}
} catch (error) {
console.error("Health check error:", error);
}
return null;
}
// Recuperare modelli
async function fetchModels() {
try {
const response = await fetch(`${API_BASE}/models`);
if (!response.ok) throw new Error("Errore nel caricamento");
const data = await response.json();
const models = data.models || [];
return {
models,
total: models.length,
totalSize: formatBytes(models.reduce((sum, m) => sum + m.size, 0)),
timestamp: new Date().toISOString()
};
} catch (error) {
console.error("Error loading models:", error);
return null;
}
}
// Sincronizzare i dati
async function syncData() {
const health = await fetchHealth();
const modelsData = await fetchModels();
// Salvare in localStorage
if (health) {
localStorage.setItem("llm_monitor_health", JSON.stringify(health));
}
if (modelsData) {
localStorage.setItem("llm_monitor_models", JSON.stringify(modelsData));
}
// Notificare il main thread
self.postMessage({
type: "DATA_UPDATED",
health,
modelsData
});
}
// Eseguire la sincronizzazione iniziale
syncData();
// Pianificare aggiornamenti periodici
setInterval(syncData, REFRESH_INTERVAL);
// Gestire messaggi dal main thread
self.onmessage = (event) => {
if (event.data.type === "SYNC_NOW") {
syncData();
}
};