Optimize home page loading by prioritizing critical data
**Motivations:** - La home est très lente au premier lancement - Tous les endpoints sont chargés en parallèle, y compris les plus lents - L'endpoint /api/utxo/list est très lent car il charge toute la liste **Root causes:** - loadData() charge 10 endpoints en parallèle sans priorisation - loadAvailableForAnchor() charge toute la liste UTXO juste pour obtenir un count - Les données moins critiques (avg fee, avg tx amount) bloquent l'affichage initial **Correctifs:** - Chargement en 2 phases : données critiques d'abord, données secondaires ensuite - Création d'un endpoint optimisé /api/utxo/count qui lit directement depuis le fichier texte - loadAvailableForAnchor() utilise maintenant l'endpoint optimisé au lieu de /api/utxo/list - Les données secondaires (avg fee, avg tx amount, avg block time) sont chargées en arrière-plan **Evolutions:** - Affichage initial plus rapide avec les données critiques - Meilleure expérience utilisateur avec chargement progressif - Endpoint optimisé pour obtenir le count sans charger toute la liste UTXO **Pages affectées:** - signet-dashboard/src/server.js : Nouvel endpoint /api/utxo/count - signet-dashboard/public/app.js : Optimisation de loadData() et loadAvailableForAnchor()
This commit is contained in:
parent
bb28499e3f
commit
548eb220da
@ -61,23 +61,32 @@ function startBlockPolling() {
|
||||
|
||||
/**
|
||||
* Charge toutes les données de supervision
|
||||
* Optimisé pour charger d'abord les données critiques, puis les données moins critiques
|
||||
*/
|
||||
async function loadData() {
|
||||
try {
|
||||
// Phase 1 : Charger les données critiques rapidement (affichage immédiat)
|
||||
await Promise.all([
|
||||
loadBlockchainInfo(),
|
||||
loadLatestBlock(),
|
||||
loadWalletBalance(),
|
||||
loadAnchorCount(),
|
||||
loadAvailableForAnchor(),
|
||||
loadNetworkPeers(),
|
||||
loadMiningDifficulty(),
|
||||
loadAvgBlockTime(),
|
||||
loadAvgFee(),
|
||||
loadAvgTxAmount(),
|
||||
]);
|
||||
|
||||
updateLastUpdateTime();
|
||||
|
||||
// Phase 2 : Charger les données moins critiques en arrière-plan (peuvent être plus lentes)
|
||||
// Ne pas attendre ces données pour mettre à jour l'heure
|
||||
Promise.all([
|
||||
loadAvailableForAnchor(),
|
||||
loadAvgBlockTime(),
|
||||
loadAvgFee(),
|
||||
loadAvgTxAmount(),
|
||||
]).catch((error) => {
|
||||
console.error('Error loading secondary data:', error);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
}
|
||||
@ -190,13 +199,13 @@ async function loadAnchorCount() {
|
||||
|
||||
/**
|
||||
* Charge la capacité d'ancrage restante
|
||||
* Utilise l'endpoint optimisé /api/utxo/count pour éviter de charger toute la liste
|
||||
*/
|
||||
async function loadAvailableForAnchor() {
|
||||
const availableForAnchorValue = document.getElementById('available-for-anchor-value');
|
||||
const availableForAnchorSpinner = document.getElementById('available-for-anchor-spinner');
|
||||
const confirmedAvailableForAnchorValue = document.getElementById('confirmed-available-for-anchor-value');
|
||||
|
||||
if (!availableForAnchorValue || !availableForAnchorSpinner || !confirmedAvailableForAnchorValue) {
|
||||
if (!availableForAnchorValue || !availableForAnchorSpinner) {
|
||||
console.error('Elements for available-for-anchor not found in DOM');
|
||||
return;
|
||||
}
|
||||
@ -204,24 +213,21 @@ async function loadAvailableForAnchor() {
|
||||
// Afficher le spinner
|
||||
availableForAnchorSpinner.style.display = 'inline';
|
||||
availableForAnchorValue.textContent = '...';
|
||||
confirmedAvailableForAnchorValue.textContent = '...';
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/utxo/list`);
|
||||
// Utiliser l'endpoint optimisé qui lit directement depuis le fichier texte
|
||||
const response = await fetch(`${API_BASE_URL}/api/utxo/count`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const counts = data.counts || {};
|
||||
const availableForAnchor = counts.availableForAnchor || 0;
|
||||
const confirmedAvailableForAnchor = counts.confirmedAvailableForAnchor || 0;
|
||||
const availableForAnchor = data.availableForAnchor || 0;
|
||||
|
||||
// Masquer le spinner et mettre à jour les valeurs
|
||||
// Masquer le spinner et mettre à jour la valeur
|
||||
availableForAnchorSpinner.style.display = 'none';
|
||||
availableForAnchorValue.textContent = availableForAnchor.toLocaleString('fr-FR') + ' ancrages';
|
||||
confirmedAvailableForAnchorValue.textContent = confirmedAvailableForAnchor.toLocaleString('fr-FR');
|
||||
} catch (error) {
|
||||
console.error('Error loading available for anchor:', error);
|
||||
// Masquer le spinner
|
||||
@ -231,7 +237,6 @@ async function loadAvailableForAnchor() {
|
||||
if (currentValue === '-' || currentValue === 'Erreur' || currentValue === '...') {
|
||||
availableForAnchorValue.textContent = '0 ancrages';
|
||||
}
|
||||
confirmedAvailableForAnchorValue.textContent = '0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -273,6 +273,60 @@ app.get('/api/hash/list.txt', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Route optimisée pour obtenir uniquement les counts UTXO (sans charger toute la liste)
|
||||
app.get('/api/utxo/count', async (req, res) => {
|
||||
try {
|
||||
const { readFileSync, existsSync } = await import('fs');
|
||||
const utxoListPath = join(__dirname, '../../utxo_list.txt');
|
||||
|
||||
if (!existsSync(utxoListPath)) {
|
||||
return res.json({
|
||||
availableForAnchor: 0,
|
||||
confirmedAvailableForAnchor: 0,
|
||||
anchors: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// Lire le fichier et compter rapidement sans parser toute la structure
|
||||
const content = readFileSync(utxoListPath, 'utf8').trim();
|
||||
const lines = content.split('\n').filter(line => line.trim());
|
||||
|
||||
let anchors = 0;
|
||||
let availableForAnchor = 0;
|
||||
let confirmedAvailableForAnchor = 0;
|
||||
const minAnchorAmount = 2000 / 100000000; // 2000 sats en BTC
|
||||
|
||||
for (const line of lines) {
|
||||
const parts = line.split(';');
|
||||
if (parts.length >= 7) {
|
||||
const category = parts[0];
|
||||
const amount = parseFloat(parts[3]) || 0;
|
||||
const confirmations = parseInt(parts[4], 10) || 0;
|
||||
const isAnchorChange = parts[5] === 'true';
|
||||
|
||||
if (category === 'anchor' && amount >= minAnchorAmount && confirmations > 0) {
|
||||
anchors++;
|
||||
// On assume que les UTXOs dans le fichier ne sont pas dépensés (isSpentOnchain serait dans un autre champ)
|
||||
// Pour être sûr, on vérifie seulement les confirmations
|
||||
availableForAnchor++;
|
||||
if (confirmations >= 6) {
|
||||
confirmedAvailableForAnchor++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
availableForAnchor,
|
||||
confirmedAvailableForAnchor,
|
||||
anchors,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error getting UTXO count', { error: error.message });
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Route pour obtenir la liste des UTXO (fichier texte)
|
||||
app.get('/api/utxo/list', async (req, res) => {
|
||||
try {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user