aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/nostrlogin.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-11 19:51:45 -0700
committerAdam Soltys <[email protected]>2026-10-11 19:51:45 -0700
commitfdaf7137139540d2f8de50b2a42d6ff3c036328b (patch)
tree28577cec63e2ced3b2cdde83288e1b234bc2dde3 /src/features/nostrlogin.js
parent491904e04fe3d69aa6b417c266aa8b550ffa0534 (diff)
downloadcoinosv3-fdaf7137139540d2f8de50b2a42d6ff3c036328b.tar.gz
coinosv3-fdaf7137139540d2f8de50b2a42d6ff3c036328b.zip
Feed: a wheel scroll through a loading feed no longer stutters on a laptop. The phone was fine (its scroll is the compositor's) but the desktop's wheel coast is driven from the main thread, so every long task froze it, and a feed that was still loading ran dozens of them: each ready post went in through its own admitFeed → holdScroll → full render (200–450 ms apiece; a Popular switch did 49 in a few seconds, one of them 1.3 s). Inside those renders the window's list getter — run on every scroll frame too — filtered every note through the mute/spam/report checks, and each check re-derived the login identity (two parses of the stored state plus a bech32 encode): 11 s of a 2-minute profile. Now ready posts are admitted together, one render per 120 ms, and while the reader is moving the page the batch waits for a quiet moment (up to 1.5 s); nostrLoginIdentity keeps its answer for 250 ms (dropped by its own saves, a signer change or another wallet's key), npubOf is memoized, modOn reads the cached messages state, the foreign-language guess is remembered per post, and the window list is reused between renders. Measured on Adam's dev tab (tools/feed-scroll-jank.js: real CDP wheel notches, chip clicks mid-load, rAF frame gaps, long tasks, a CPU profile that names each busy stretch): stalled time during a switch 1.9–2.5 s → 0–83 ms, no frame over 50 ms on the wheel path, main thread busy 33% → 17%; settled scrolling was already clean. feed-streaming's "tap reveals the oldest ready new post" fails on the previous commit too.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'src/features/nostrlogin.js')
-rw-r--r--src/features/nostrlogin.js18
1 files changed, 14 insertions, 4 deletions
diff --git a/src/features/nostrlogin.js b/src/features/nostrlogin.js
index f18b075..f7f9e16 100644
--- a/src/features/nostrlogin.js
+++ b/src/features/nostrlogin.js
@@ -28,7 +28,13 @@ export function nostrLoginFeature(ctx) {
const { h, ui, render, wallet, toast, copyBtn } = ctx;
const load = () => wallet.loadFeatureState('nostrlogin', {});
- const save = (st) => wallet.saveFeatureState('nostrlogin', st);
+ const save = (st) => { idMemo = null; wallet.saveFeatureState('nostrlogin', st); };
+ // nostrLoginIdentity() is asked per feed row per moderation check (isMe,
+ // mePk, trusted…): thousands of times per scroll frame. Each answer parsed
+ // the stored state twice and bech32-encoded the npub. Keep the last answer
+ // briefly; a save, a signer change or another wallet's key drops it.
+ let idMemo = null;
+ const ID_MEMO_MS = 250;
// The signer that opened this session, kept so the names feature can claim
// the user's real npub as their payment address (and nominate the wallet
@@ -765,10 +771,14 @@ export function nostrLoginFeature(ctx) {
// wallet key's face in the gap.
// `via`: how the account came in, known before its signer wakes (an
// Amber account is one whether or not Amber has been asked anything yet)
+ const key = wallet.featureStateKey('nostrlogin');
+ if (idMemo && idMemo.live === live && idMemo.key === key && Date.now() - idMemo.at < ID_MEMO_MS) return idMemo.value;
const st = load();
- if (liveSigner()) return { pubkey: live.pubkey, npub: npubOf(live.pubkey), signer: live, via: st.pubkey === live.pubkey ? reconnectViaOf(st) : viaOf(live) };
- if (!st.pubkey) return null;
- return { pubkey: st.pubkey, npub: npubOf(st.pubkey), signer: live, via: reconnectViaOf(st) };
+ let value = null;
+ if (liveSigner()) value = { pubkey: live.pubkey, npub: npubOf(live.pubkey), signer: live, via: st.pubkey === live.pubkey ? reconnectViaOf(st) : viaOf(live) };
+ else if (st.pubkey) value = { pubkey: st.pubkey, npub: npubOf(st.pubkey), signer: live, via: reconnectViaOf(st) };
+ idMemo = { at: Date.now(), live, key, value };
+ return value;
},
// A page reload loses the signer. A stored passkey key or an installed
// extension reattaches without prompting, which is what lets the payment