Skip to content

Tiles view: previews are fetched at 1000x1000 and never released #3167

Description

@JammingBen

Part of the file list scroll performance work for #3159.

Current situation

ImageDimension.Tile is [1000, 1000] (packages/web-pkg/src/constants.ts). Each tile thumbnail is a ~816 KB response, decoded into roughly 4 MB of bitmap, and displayed in a 316x178 px box.

On top of that:

  • previewService.privatePreviewBlob calls window.URL.createObjectURL() but nothing ever revokes those URLs, so no preview is ever freed
  • itemVisible queues a preview for every item the user scrolls past, and nothing cancels queued work for items that have left the viewport
  • cacheService.filePreview has a capacity of 250 for a 500-item page, so the second half evicts the first and previews are re-fetched when scrolling back
  • Cache.evict() walks the whole map on every get and set
  • useLoadPreview creates its own PQueue per caller, so concurrency is not bounded globally

Measured on a 500-image folder (items per page 500):

Scenario Engine Median frame Tiles filled in 4 s
Tiles, baseline WebKit 80 ms 108
Tiles, preview requests blocked WebKit 32 ms 348
Tiles, baseline Chromium 18 ms 448
Tiles, preview requests blocked Chromium 10 ms 500

Sampled response: processor=fit&x=1000&y=1000, 836,221 bytes, 37-41 ms each. 500 tiles is roughly 400 MB of image data.

The table view is much less affected (WebKit 47 ms → 39 ms) because table thumbnails are 36x36.

Why this is bad

Preview loading is the single biggest cost in the tiles view on Safari - roughly 60% of the frame time. The unbounded memory growth also degrades long sessions, and re-fetching on scroll-back wastes bandwidth and puts avoidable load on the thumbnails service.

Proposed solution

  1. Derive the tile preview size from the rendered tile size multiplied by devicePixelRatio and capped - roughly 640x640 instead of 1000x1000. Leave ImageDimension.Preview alone for the preview app and SpaceHeader. perf: dynamic tile preview dimensions #3192
  2. Revoke object URLs when a preview cache entry is evicted or replaced, and when the resource list is cleared. perf: preview cache optimizations #3194
  3. Raise the preview cache capacity to at least the page size so scrolling back does not re-fetch, and replace the O(n) evict() walk with lazy expiry plus proper LRU ordering. perf: preview cache optimizations #3194
  4. Make the preview queue viewport-aware: drop or deprioritize queued items that are no longer visible, and share one queue across the list instead of one per useLoadPreview caller. perf: drop queued previews leaving the viewport #3198
  5. Set decoding="async" on OcImages for loading thumbnails (in: ResourceTile, ResourceListItem and Projects). perf: decode thumbnails asynchronously #3204

Verification

  • Safari tiles median frame time approaching the 32 ms measured with previews blocked
  • transferred preview bytes for a 500-item folder down by roughly 4x
  • JS heap flat after scrolling down and back up

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions