feat: make friends highlights loading non-blocking

- Start fetching highlights immediately when partial contacts arrive
- Track seen authors to avoid duplicate queries
- Fire-and-forget pattern for partial fetches (like bookmark loading)
- Only await final batch for remaining authors
- Highlights stream in progressively as contacts are discovered
- Matches the non-blocking pattern used in Explore.tsx and bookmark loading
This commit is contained in:
Gigi
2025-10-18 20:47:35 +02:00
parent 1ff2f28566
commit 8030e2fa00

View File

@@ -469,22 +469,58 @@ const Debug: React.FC<DebugProps> = ({
setIsLoadingHighlights(true)
setTLoadHighlights(null)
setTFirstHighlight(null)
DebugBus.info('debug', 'Loading friends highlights...')
DebugBus.info('debug', 'Loading friends highlights (non-blocking)...')
let firstEventTime: number | null = null
const seenAuthors = new Set<string>()
try {
const contacts = await fetchContacts(relayPool, activeAccount.pubkey)
DebugBus.info('debug', `Found ${contacts.size} friends`)
let firstEventTime: number | null = null
await fetchHighlightsFromAuthors(relayPool, Array.from(contacts), (h) => {
if (firstEventTime === null) {
firstEventTime = performance.now() - start
setTFirstHighlight(Math.round(firstEventTime))
const contacts = await fetchContacts(
relayPool,
activeAccount.pubkey,
(partial) => {
// Non-blocking: start fetching as soon as we get partial contacts
if (partial.size > 0) {
const partialArray = Array.from(partial).filter(pk => !seenAuthors.has(pk))
if (partialArray.length > 0) {
partialArray.forEach(pk => seenAuthors.add(pk))
DebugBus.info('debug', `Fetching highlights from ${partialArray.length} friends (${seenAuthors.size} total)`)
// Fire and forget - don't await
fetchHighlightsFromAuthors(relayPool, partialArray, (h) => {
if (firstEventTime === null) {
firstEventTime = performance.now() - start
setTFirstHighlight(Math.round(firstEventTime))
}
setHighlightEvents(prev => {
if (prev.some(x => x.id === h.id)) return prev
const next = [...prev, { ...h, pubkey: h.pubkey, created_at: h.created_at, id: h.id, kind: 9802, tags: [], content: h.content, sig: '' } as NostrEvent]
return next.sort((a, b) => b.created_at - a.created_at)
})
}).catch(err => console.error('Error fetching highlights from partial:', err))
}
}
}
setHighlightEvents(prev => {
if (prev.some(x => x.id === h.id)) return prev
const next = [...prev, { ...h, pubkey: h.pubkey, created_at: h.created_at, id: h.id, kind: 9802, tags: [], content: h.content, sig: '' } as NostrEvent]
return next.sort((a, b) => b.created_at - a.created_at)
)
DebugBus.info('debug', `Found ${contacts.size} total friends`)
// Fetch any remaining authors not covered by partials
const finalAuthors = Array.from(contacts).filter(pk => !seenAuthors.has(pk))
if (finalAuthors.length > 0) {
DebugBus.info('debug', `Fetching highlights from ${finalAuthors.length} remaining friends`)
await fetchHighlightsFromAuthors(relayPool, finalAuthors, (h) => {
if (firstEventTime === null) {
firstEventTime = performance.now() - start
setTFirstHighlight(Math.round(firstEventTime))
}
setHighlightEvents(prev => {
if (prev.some(x => x.id === h.id)) return prev
const next = [...prev, { ...h, pubkey: h.pubkey, created_at: h.created_at, id: h.id, kind: 9802, tags: [], content: h.content, sig: '' } as NostrEvent]
return next.sort((a, b) => b.created_at - a.created_at)
})
})
})
}
} finally {
setIsLoadingHighlights(false)
const elapsed = Math.round(performance.now() - start)