[fix](trx-frontend-http): skip redundant DOM writes in render() hot path

The render() function runs on every SSE event (5-20×/sec) and was
unconditionally writing to decoder toggle buttons and About-tab
decoder status elements — 8 getElementById calls + 32 DOM property
writes per frame — even when values hadn't changed. This caused
unnecessary style recalculation overhead on every SSE frame,
contributing to spectrum stuttering.

Changes:
- Cache all 7 decoder toggle button elements at module init instead
  of calling getElementById on every render() call
- Track last-written enabled state per button; skip DOM writes when
  the value is unchanged (steady-state cost: 0 DOM writes per frame)
- Same pattern for 8 About-tab decoder status elements
- Gate updateSatLiveState className/textContent writes on value change

Net effect: eliminates ~50 unnecessary DOM operations per SSE frame
during normal operation (decoders rarely toggle).

https://claude.ai/code/session_01G6wuNCkckbHHsU7w5zCtW2
Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Claude
2026-03-28 18:08:16 +00:00
committed by Stan Grams
parent aacc7336d7
commit 731410a7e6
2 changed files with 63 additions and 79 deletions
@@ -363,6 +363,41 @@ const headerStylePickSelect = document.getElementById("header-style-pick-select"
const rdsPsOverlay = document.getElementById("rds-ps-overlay");
let overviewPeakHoldMs = Number(loadSetting("overviewPeakHoldMs", 2000));
let decodeHistoryRetentionMin = 24 * 60;
// Cached decoder toggle buttons — avoids 8× getElementById per render() call.
const _decoderToggles = {
ft8: { el: document.getElementById("ft8-decode-toggle-btn"), last: null },
ft4: { el: document.getElementById("ft4-decode-toggle-btn"), last: null },
ft2: { el: document.getElementById("ft2-decode-toggle-btn"), last: null },
wspr: { el: document.getElementById("wspr-decode-toggle-btn"), last: null },
hfAprs: { el: document.getElementById("hf-aprs-decode-toggle-btn"), last: null },
sat: { el: document.getElementById("sat-decode-toggle-btn"), last: null },
lrpt: { el: document.getElementById("lrpt-decode-toggle-btn"), last: null },
};
function syncDecoderToggle(entry, enabled, label) {
if (!entry.el || entry.last === enabled) return;
entry.last = enabled;
entry.el.dataset.enabled = enabled ? "true" : "false";
entry.el.textContent = enabled ? `Disable ${label}` : `Enable ${label}`;
entry.el.style.borderColor = enabled ? "#00d17f" : "";
entry.el.style.color = enabled ? "#00d17f" : "";
}
// Cached About-tab decoder status elements — avoids 8× getElementById per render().
const _aboutDecEls = [
"about-dec-ft8", "about-dec-ft4", "about-dec-ft2", "about-dec-wspr",
"about-dec-cw", "about-dec-aprs", "about-dec-sat", "about-dec-lrpt",
].map((id) => ({ el: document.getElementById(id), last: null }));
function syncAboutDecoder(idx, enabled) {
const entry = _aboutDecEls[idx];
if (!entry || !entry.el || entry.last === enabled) return;
entry.last = enabled;
entry.el.textContent = enabled ? "Active" : "Off";
entry.el.className = enabled ? "about-status-on" : "about-status-off";
}
let primaryRds = null;
let vchanRdsById = new Map();
let vchanSignalDbById = new Map();
@@ -3229,62 +3264,14 @@ function render(update) {
pttBtn.style.color = "";
}
}
const ft8ToggleBtn = document.getElementById("ft8-decode-toggle-btn");
if (ft8ToggleBtn) {
const ft8On = !!update.ft8_decode_enabled;
ft8ToggleBtn.dataset.enabled = ft8On ? "true" : "false";
ft8ToggleBtn.textContent = ft8On ? "Disable FT8" : "Enable FT8";
ft8ToggleBtn.style.borderColor = ft8On ? "#00d17f" : "";
ft8ToggleBtn.style.color = ft8On ? "#00d17f" : "";
}
const ft4ToggleBtn = document.getElementById("ft4-decode-toggle-btn");
if (ft4ToggleBtn) {
const ft4On = !!update.ft4_decode_enabled;
ft4ToggleBtn.dataset.enabled = ft4On ? "true" : "false";
ft4ToggleBtn.textContent = ft4On ? "Disable FT4" : "Enable FT4";
ft4ToggleBtn.style.borderColor = ft4On ? "#00d17f" : "";
ft4ToggleBtn.style.color = ft4On ? "#00d17f" : "";
}
const ft2ToggleBtn = document.getElementById("ft2-decode-toggle-btn");
if (ft2ToggleBtn) {
const ft2On = !!update.ft2_decode_enabled;
ft2ToggleBtn.dataset.enabled = ft2On ? "true" : "false";
ft2ToggleBtn.textContent = ft2On ? "Disable FT2" : "Enable FT2";
ft2ToggleBtn.style.borderColor = ft2On ? "#00d17f" : "";
ft2ToggleBtn.style.color = ft2On ? "#00d17f" : "";
}
const wsprToggleBtn = document.getElementById("wspr-decode-toggle-btn");
if (wsprToggleBtn) {
const wsprOn = !!update.wspr_decode_enabled;
wsprToggleBtn.dataset.enabled = wsprOn ? "true" : "false";
wsprToggleBtn.textContent = wsprOn ? "Disable WSPR" : "Enable WSPR";
wsprToggleBtn.style.borderColor = wsprOn ? "#00d17f" : "";
wsprToggleBtn.style.color = wsprOn ? "#00d17f" : "";
}
const hfAprsToggleBtn = document.getElementById("hf-aprs-decode-toggle-btn");
if (hfAprsToggleBtn) {
const hfAprsOn = !!update.hf_aprs_decode_enabled;
hfAprsToggleBtn.dataset.enabled = hfAprsOn ? "true" : "false";
hfAprsToggleBtn.textContent = hfAprsOn ? "Disable HF APRS" : "Enable HF APRS";
hfAprsToggleBtn.style.borderColor = hfAprsOn ? "#00d17f" : "";
hfAprsToggleBtn.style.color = hfAprsOn ? "#00d17f" : "";
}
const satToggleBtn = document.getElementById("sat-decode-toggle-btn");
if (satToggleBtn) {
const satOn = !!update.wxsat_decode_enabled;
satToggleBtn.dataset.enabled = satOn ? "true" : "false";
satToggleBtn.textContent = satOn ? "Disable NOAA APT" : "Enable NOAA APT";
satToggleBtn.style.borderColor = satOn ? "#00d17f" : "";
satToggleBtn.style.color = satOn ? "#00d17f" : "";
}
const lrptToggleBtn = document.getElementById("lrpt-decode-toggle-btn");
if (lrptToggleBtn) {
const lrptOn = !!update.lrpt_decode_enabled;
lrptToggleBtn.dataset.enabled = lrptOn ? "true" : "false";
lrptToggleBtn.textContent = lrptOn ? "Disable Meteor LRPT" : "Enable Meteor LRPT";
lrptToggleBtn.style.borderColor = lrptOn ? "#00d17f" : "";
lrptToggleBtn.style.color = lrptOn ? "#00d17f" : "";
}
// Decoder toggle buttons: only write DOM when the enabled flag actually changes.
syncDecoderToggle(_decoderToggles.ft8, !!update.ft8_decode_enabled, "FT8");
syncDecoderToggle(_decoderToggles.ft4, !!update.ft4_decode_enabled, "FT4");
syncDecoderToggle(_decoderToggles.ft2, !!update.ft2_decode_enabled, "FT2");
syncDecoderToggle(_decoderToggles.wspr, !!update.wspr_decode_enabled, "WSPR");
syncDecoderToggle(_decoderToggles.hfAprs, !!update.hf_aprs_decode_enabled, "HF APRS");
syncDecoderToggle(_decoderToggles.sat, !!update.wxsat_decode_enabled, "NOAA APT");
syncDecoderToggle(_decoderToggles.lrpt, !!update.lrpt_decode_enabled, "Meteor LRPT");
if (window.updateSatLiveState) window.updateSatLiveState(update);
const cwAutoEl = document.getElementById("cw-auto");
const cwWpmEl = document.getElementById("cw-wpm");
@@ -3453,24 +3440,15 @@ function render(update) {
document.getElementById("about-audio-streams").textContent = update.audio_clients;
}
// About — Decoders card
const decMap = [
["about-dec-ft8", update.ft8_decode_enabled],
["about-dec-ft4", update.ft4_decode_enabled],
["about-dec-ft2", update.ft2_decode_enabled],
["about-dec-wspr", update.wspr_decode_enabled],
["about-dec-cw", update.cw_decode_enabled],
["about-dec-aprs", update.aprs_decode_enabled || update.hf_aprs_decode_enabled],
["about-dec-sat", update.wxsat_decode_enabled],
["about-dec-lrpt", update.lrpt_decode_enabled],
];
for (const [id, enabled] of decMap) {
const el = document.getElementById(id);
if (el) {
el.textContent = enabled ? "Active" : "Off";
el.className = enabled ? "about-status-on" : "about-status-off";
}
}
// About — Decoders card (only update when values change)
syncAboutDecoder(0, !!update.ft8_decode_enabled);
syncAboutDecoder(1, !!update.ft4_decode_enabled);
syncAboutDecoder(2, !!update.ft2_decode_enabled);
syncAboutDecoder(3, !!update.wspr_decode_enabled);
syncAboutDecoder(4, !!update.cw_decode_enabled);
syncAboutDecoder(5, !!(update.aprs_decode_enabled || update.hf_aprs_decode_enabled));
syncAboutDecoder(6, !!update.wxsat_decode_enabled);
syncAboutDecoder(7, !!update.lrpt_decode_enabled);
// About — Integrations card
if (update.pskreporter_status) {
@@ -73,15 +73,21 @@ satViewPredictionsBtn?.addEventListener("click", () => switchSatView("prediction
// ── Live view: decoder state ────────────────────────────────────────
// Updated from app.js render() via window.updateSatLiveState
let _lastSatAptOn = null, _lastSatLrptOn = null;
window.updateSatLiveState = function (update) {
if (!satAptState || !satLrptState) return;
const aptOn = !!update.wxsat_decode_enabled;
const lrptOn = !!update.lrpt_decode_enabled;
if (aptOn !== _lastSatAptOn) {
_lastSatAptOn = aptOn;
satAptState.textContent = aptOn ? "Listening" : "Idle";
satAptState.className = "sat-live-value " + (aptOn ? "sat-state-listening" : "sat-state-idle");
}
if (lrptOn !== _lastSatLrptOn) {
_lastSatLrptOn = lrptOn;
satLrptState.textContent = lrptOn ? "Listening" : "Idle";
satLrptState.className = "sat-live-value " + (lrptOn ? "sat-state-listening" : "sat-state-idle");
}
};
function renderSatLatestCard() {