perf: show artist hero after 2 fast calls instead of waiting for all 6

Split the allSettled into two phases: await imgP+albumP first (both are
fast — getArtistImage hits S.artistImgCache when navigating from the
listing, getArtist is a local Navidrome call), then reveal the hero.
The slow calls (getArtistInfo2 / Last.fm bio, iTunes search, events)
keep running in parallel and are only awaited when rendering the content
sections below the hero — so the user sees the hero card immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-06-08 20:42:03 +02:00
1 parent 1f9495f806
commit c8e3f5b641
1 file changed
+15 -10
+15 -10
View File
@@ -86,16 +86,21 @@ export async function loadArtistDetail(artist) {
const hasND = !!artist.id;
const knownItunes = artist.itunesArtistId || null;
const [imgRes, albumRes, infoRes, topRes, iArtistRes, eventsRes] = await Promise.allSettled([
hasND ? getArtistImage(artist.id) : Promise.resolve(null),
hasND ? api('getArtist', `&id=${artist.id}`) : Promise.resolve(null),
hasND ? api('getArtistInfo2',`&id=${artist.id}&count=8`) : Promise.resolve(null),
hasND ? api('getTopSongs', `&artist=${encodeURIComponent(artist.name)}&count=10`) : Promise.resolve(null),
knownItunes
? Promise.resolve([{ artistId: knownItunes }])
: itunesSearch(artist.name, 'musicArtist', 5),
fetchEvents(artist.name),
]);
// Fire all requests immediately so they run in parallel.
// Hero only needs imgP + albumP (both fast / usually cached) — await those
// first so the hero appears instantly without waiting for iTunes or events.
const imgP = hasND ? getArtistImage(artist.id) : Promise.resolve(null);
const albumP = hasND ? api('getArtist', `&id=${artist.id}`) : Promise.resolve(null);
const infoP = hasND ? api('getArtistInfo2',`&id=${artist.id}&count=8`) : Promise.resolve(null);
const topP = hasND ? api('getTopSongs', `&artist=${encodeURIComponent(artist.name)}&count=10`) : Promise.resolve(null);
const iArtistP = knownItunes ? Promise.resolve([{ artistId: knownItunes }]) : itunesSearch(artist.name, 'musicArtist', 5);
const eventsP = fetchEvents(artist.name);
// Phase 1 — hero (fast: image usually cached from listing, getArtist is local)
const [imgRes, albumRes] = await Promise.allSettled([imgP, albumP]);
// Phase 2 — content (may be slow: Last.fm bio, iTunes, events)
const [infoRes, topRes, iArtistRes, eventsRes] = await Promise.allSettled([infoP, topP, iArtistP, eventsP]);
const _normWords = s => new Set((s || '').toLowerCase().replace(/[^a-z0-9]/g, ' ').split(/\s+/).filter(Boolean));
const _queryWords = _normWords(artist.name);