Jittery scrolling through unread posts #228

Closed
opened 2026-10-21 19:04:37 +00:00 by littlefox · 2 comments
Owner

Reported by the user (D-057): scrolling quickly through unread posts jitters. The user suspects marking posts read makes the UI wait for something.

What the code does today (#180):

  • SEEN_JS in app/src/main_view/mod.rs runs every 250 ms. It calls getBoundingClientRect on every unread card, which forces layout while you scroll.
  • Each card seen goes to Rust. Rust awaits kom.mark_read (a server round trip), then bumps tick.
  • Bumping tick reloads and re-renders the whole thread (see the redraw issue). That probably causes the jitter more than the round trip itself does.
  • JUST_SEEN is written for every card, which also re-renders the thread.

Directions:

  • Use an IntersectionObserver instead of polling layout.
  • Batch the marks, and mark the cards read locally right away, sending to the server in the background.
  • Let a mark not reload the thread.

Done when: scrolling quickly through a few hundred unread cards has no long tasks (the measuring spec) and looks smooth on desktop and phone.

Reported by the user (D-057): scrolling quickly through unread posts jitters. The user suspects marking posts read makes the UI wait for something. What the code does today (#180): - `SEEN_JS` in `app/src/main_view/mod.rs` runs every 250 ms. It calls `getBoundingClientRect` on every unread card, which forces layout while you scroll. - Each card seen goes to Rust. Rust awaits `kom.mark_read` (a server round trip), then bumps `tick`. - Bumping `tick` reloads and re-renders the whole thread (see the redraw issue). That probably causes the jitter more than the round trip itself does. - `JUST_SEEN` is written for every card, which also re-renders the thread. Directions: - Use an `IntersectionObserver` instead of polling layout. - Batch the marks, and mark the cards read locally right away, sending to the server in the background. - Let a mark not reload the thread. Done when: scrolling quickly through a few hundred unread cards has no long tasks (the measuring spec) and looks smooth on desktop and phone.
Author
Owner

More from the codebase review (#230):

  • SEEN_JS runs every 250 ms even when nothing scrolls (#233).
  • Each mark is its own mark-as-read call; batching them is in #234.
  • Each mark also writes JUST_SEEN and bumps tick, both of which redraw the thread (#226).
More from the codebase review (#230): - `SEEN_JS` runs every 250 ms even when nothing scrolls (#233). - Each mark is its own `mark-as-read` call; batching them is in #234. - Each mark also writes `JUST_SEEN` and bumps `tick`, both of which redraw the thread (#226).
Author
Owner

Merged in #254; main run #426 green. Verified: full e2e suite on three profiles (327 passed) and tools/perf.sh against the baseline. Reading 120 cards by scrolling past them: server calls 287 → 99, layouts 119 → 35, style recalcs 126 → 61, main-thread time 1.2 → 0.37 s. Reading 300 posts along the chain: style recalcs −33 %. Idle main-thread time 0.03 → 0.01 s per 20 s.

Merged in #254; main run #426 green. Verified: full e2e suite on three profiles (327 passed) and `tools/perf.sh` against the baseline. Reading 120 cards by scrolling past them: server calls 287 → 99, layouts 119 → 35, style recalcs 126 → 61, main-thread time 1.2 → 0.37 s. Reading 300 posts along the chain: style recalcs −33 %. Idle main-thread time 0.03 → 0.01 s per 20 s.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
littlefox/neokom#228
No description provided.