Skip to content

Web client: main thread saturated by synchronous JS (native mobile instant on same account/server) #1765

Open

Description

@f-liva

Summary

On the web client, the UI becomes very sluggish (session list navigation and opening a session), while the native mobile app on the same account and the same self-hosted server is instant. A Chrome Performance profile shows the main thread is saturated by synchronous JS, not by rendering, network, or the server.

Environment

  • Self-hosted server (happy-server), web client served over HTTPS.
  • Chrome (latest) on Windows desktop.
  • Native mobile app: same account, same server → fast. So the bottleneck is client-side in the web build, not the backend or the link.

Profile (Chrome DevTools → Performance, ~36 s capture: session-list scroll + opening one session)

Summary:

  • Scripting 23,374 ms
  • Rendering 111 ms
  • Painting 79 ms
  • System 4,283 ms
  • Total 36,350 ms

→ Rendering/painting are negligible; it's ~64% Scripting. The main thread is blocked by JS, so the tab (and even DevTools itself) stutters.

Bottom-Up (Self time):

  • evaluate — 16,039 ms (61.3%)
  • Major GC — 1,312 ms (5.0%) ← heavy allocation churn
  • Function call index-0ed1099…js:1026:546 — 707 ms self / 6,439 ms total (24.4%) (app hot path, minified)
  • nextNode — 699 ms

The combination of a dominant evaluate self-time plus significant Major GC points at large synchronous work with high allocation — consistent with decrypting/parsing many sessions and re-deriving/re-sorting large in-memory structures on the main thread.

Ruling things out

  • Extensions are not the cause: repeated in a clean Incognito window (extensions disabled) — identical slowness. In the profiled run, extension main-thread time was tiny (Bitwarden ~640 ms, everything else <100 ms), ~3% of Scripting.
  • Not the server / network: the native app hits the same server and is instant.

Likely related

These describe specific prefetch paths; this report is about the web client's overall main-thread saturation (session list + session open), which may share the same root cause (whole datasets decrypted/parsed/sorted synchronously on the main thread).

Questions

  1. Is the session list and/or session open decrypting and parsing the full dataset synchronously on the main thread? Given sessions.json on our machine is ~210 KB with many sessions, that would explain the evaluate + Major GC signature.
  2. Would offloading decrypt/parse to a Web Worker (or chunking + requestIdleCallback) be acceptable, so the main thread stays responsive on web the way the native app already is?

Happy to capture a deeper trace (expanded call tree under index-…js:1026:546, an exported .json trace, or an unminified profile against a dev build) if that helps pinpoint the hot function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions