[fix](trx-frontend-http): reduce INP on freq input from ~1500ms to <50ms
Chrome classifies wheel events as "pointer" interactions and tracks async
continuations initiated by the handler. The wheel-on-freq-input path was:
jogFreq → setRigFrequency → postPath(/set_freq) [~700ms]
→ ensureTunedBandwidthCoverage [~700ms]
...two sequential network round-trips totalling ~1400ms of INP.
Three changes:
1. yieldToMain(): add a scheduler.yield() / setTimeout(0) helper that
yields the main thread back to the browser. Chrome's INP interaction
tracking ends at the yield point, so the network RTT no longer counts.
2. jogFreq: call applyLocalTunedFrequency() optimistically before the
yield so the freq display updates are visible in the very next paint,
then yield before firing any network requests.
3. setRigFrequency: move applyLocalTunedFrequency() before the awaits
(consistent optimistic-update contract for all callers), and run
postPath(/set_freq) and ensureTunedBandwidthCoverage() in parallel
via Promise.all — they are independent server operations.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -1457,9 +1457,13 @@ async function setRigFrequency(freqHz) {
|
||||
showUnsupportedFreqPopup(targetHz);
|
||||
throw new Error(`Unsupported frequency: ${targetHz}`);
|
||||
}
|
||||
await postPath(`/set_freq?hz=${targetHz}`);
|
||||
// Optimistic local update before any network round-trip.
|
||||
applyLocalTunedFrequency(targetHz);
|
||||
await ensureTunedBandwidthCoverage(targetHz);
|
||||
// set_freq and set_center_freq are independent server operations — run in parallel.
|
||||
await Promise.all([
|
||||
postPath(`/set_freq?hz=${targetHz}`),
|
||||
ensureTunedBandwidthCoverage(targetHz),
|
||||
]);
|
||||
}
|
||||
|
||||
function spectrumBinIndexForHz(data, hz) {
|
||||
@@ -2750,6 +2754,15 @@ function disconnect() {
|
||||
}
|
||||
}
|
||||
|
||||
// Yield the main thread so the browser can paint before heavy async work.
|
||||
// Uses scheduler.yield() (Chrome 115+) with a setTimeout fallback.
|
||||
function yieldToMain() {
|
||||
if (typeof scheduler !== "undefined" && typeof scheduler.yield === "function") {
|
||||
return scheduler.yield();
|
||||
}
|
||||
return new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
|
||||
async function postPath(path) {
|
||||
const resp = await fetch(path, { method: "POST" });
|
||||
if (authEnabled && resp.status === 401) {
|
||||
@@ -2949,6 +2962,11 @@ async function jogFreq(direction) {
|
||||
jogAngle = (jogAngle + direction * 15) % 360;
|
||||
jogIndicator.style.transform = `translateX(-50%) rotate(${jogAngle}deg)`;
|
||||
showHint("Setting frequency…");
|
||||
// Optimistic local state update — visible to the user before the network call.
|
||||
applyLocalTunedFrequency(newHz);
|
||||
// Yield so the browser paints the updated freq display before the network
|
||||
// round-trip begins. Chrome's INP tracking ends at the yield point.
|
||||
await yieldToMain();
|
||||
try {
|
||||
await setRigFrequency(newHz);
|
||||
showHint("Freq set", 1000);
|
||||
|
||||
Reference in New Issue
Block a user