diff options
| author | Adam Soltys <[email protected]> | 2026-09-03 22:36:29 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-03 22:36:29 -0700 |
| commit | 3792c8791773d5201356d5fcc5f449ddd08e7a71 (patch) | |
| tree | 8735ce3a1565637db317686059b43e223e20c119 /src | |
| parent | 231d1e21ede495e283778c3a630598b2308af5f5 (diff) | |
| download | coinosv3-3792c8791773d5201356d5fcc5f449ddd08e7a71.tar.gz coinosv3-3792c8791773d5201356d5fcc5f449ddd08e7a71.zip | |
The post-refresh carousel stutter, root-caused and fixed: a CPU profile of the exact cold first-drag window showed ~700ms of secp256k1, and it was the COMMUNITY room's gift-wrap decryption — a relay backlog of 500+ wraps decrypted inline in the subscription callbacks, one synchronous EC burst on boot (the DM inbox already yielded; community rooms didn't). Now their decrypt work is time-sliced through the same yield-every-8ms queue, so it spreads over a few frames and the wallet stays responsive. Measured: first cold flick dropped 6 frames before, and this was the dominant cost
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MrkLsNScXe9b6BviUSdmMr
Diffstat (limited to 'src')
| -rw-r--r-- | src/features/messages.js | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index fe20ac4..790f33c 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -315,6 +315,30 @@ export function messagesFeature(ctx) { return npub ? npub.slice(0, 12) : pk.slice(0, 12); }; + // Community wraps decrypt with real secp256k1 work (NIP-44), and a relay + // backlog delivers hundreds at once. Decrypting them inline in the + // subscription callbacks blocked the main thread in one burst on boot — the + // stutter felt when dragging the balance carousel right after a refresh. + // Queue the decrypt work and run it time-sliced: ~8ms of work, then yield so + // input and paint get a turn. Chat catches up a few frames later; the wallet + // stays responsive. (Same pattern the DM inbox drain already uses.) + const roomWork = []; + let roomWorking = false; + function enqueueRoomWork(fn) { + roomWork.push(fn); + if (roomWorking) return; + roomWorking = true; + (async () => { + try { + let t0 = performance.now(); + while (roomWork.length) { + try { roomWork.shift()(); } catch {} + if (performance.now() - t0 > 8) { await new Promise((r) => setTimeout(r)); t0 = performance.now(); } + } + } finally { roomWorking = false; } + })(); + } + // ---- community rooms ---------------------------------------------------- function ensureRoom(jm) { @@ -376,18 +400,22 @@ export function messagesFeature(ctx) { subscribeOn(room.relays, { kinds: [1059], authors: [room.control.pk], limit: 500 }, (wrap) => { if (seenWraps.has(wrap.id)) return; seenWraps.add(wrap.id); - const opened = openWrap(wrap, room.control); - if (!opened || opened.rumor.kind !== 3308) return; - room.controlEntries.push(opened); - scheduleFold(); + enqueueRoomWork(() => { + const opened = openWrap(wrap, room.control); + if (!opened || opened.rumor.kind !== 3308) return; + room.controlEntries.push(opened); + scheduleFold(); + }); }), subscribeOn(room.relays, { kinds: [1059], authors: [room.guestbook.pk], limit: 500 }, (wrap) => { if (seenWraps.has(wrap.id)) return; seenWraps.add(wrap.id); - const opened = openWrap(wrap, room.guestbook); - if (!opened) return; - room.guestEntries.push(opened); - scheduleFold(); + enqueueRoomWork(() => { + const opened = openWrap(wrap, room.guestbook); + if (!opened) return; + room.guestEntries.push(opened); + scheduleFold(); + }); }) ); for (const c of jm.channels || []) subChannel(room, c.id); @@ -408,9 +436,11 @@ export function messagesFeature(ctx) { allUnsubs.push(subscribeOn(room.relays, { kinds: [1059, 21059], authors: [room.chStream(id).pk], limit: 200 }, (wrap) => { if (seenWraps.has(wrap.id)) return; seenWraps.add(wrap.id); - const opened = openWrap(wrap, room.chStream(id)); - if (!opened) return; - onChat(room, id, opened); + enqueueRoomWork(() => { + const opened = openWrap(wrap, room.chStream(id)); + if (!opened) return; + onChat(room, id, opened); + }); })); } |
