perf(library): pre-warm songs cache + off-thread fetch#165
Merged
Conversation
First browse to the Songs segment on a big library hung ~1s: the cold fetch ran synchronously during render, and the one-shot startup pre-warm was invalidated by the post-startup album-detail walk advancing songIndexStore.mutationCounter. - Async fetch (getAllAsync, chunked mapping) so the SQLite read and row mapping never block the JS thread. - Hook returns a loading flag and fills the cache async on a cold miss; warm hits stay synchronous/instant. In-flight fetches are shared. - Resilient auto-warmer: initial warm after interactions, then a debounced re-warm on every song-index mutation, run on idle. Replaces the invalidated queueMicrotask warm in rehydrate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the ~1s hang on the first browse to the Library Songs segment on a big library.
Root cause: the songs list was fetched synchronously on the JS thread during render (
getAllSync+ row→Childmapping), and the existing one-shot startup pre-warm was invalidated by the post-startup album-detail walk advancingsongIndexStore.mutationCounter— re-arming the cold fetch before the user reached the segment.Changes
fetchAllSongsByTitleAsync()reads via expo-sqlitegetAllAsync(background native thread) with the row mapping chunked (2000-row slices +setTimeout(0)yields), so neither stage blocks the JS thread. Sync variant kept for sync callers/tests;InternalDbgainsgetAllAsync.useAllSongsByTitlereturns the warm cache synchronously/instantly; a cold miss returns[]+loadingand fills async, re-rendering when ready. In-flight fetches are shared (a cold mount racing the auto-warmer awaits the same fetch).startSongLibraryCacheAutoWarm(): initial warm after startup interactions, then a debounced (2s) re-warm on everymutationCounterchange, run on idle. Survives the album-detail walk that invalidated the old warm. Started fromrunDeferredStartup; removed thequeueMicrotaskwarm inrehydrate.ts.loading.Testing
tsc --noEmitclean