Merge pull request #2192 from PR0M3TH3AN/perf/batch-profile-refresh-14711465702211977594

⚡ Optimize profile refreshing with batch requests
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-07 18:18:50 -05:00
commit c290959a7e
3 files changed
+83 -4

No files matched your search

+3 -4
View File
@@ -718,9 +718,7 @@ class Application {
const uniqueAuthors = new Set(activeVideos.map((v) => v.pubkey));
// 3) For each author, fetchAndRenderProfile with forceRefresh = true
for (const authorPubkey of uniqueAuthors) {
this.authService.fetchAndRenderProfile(authorPubkey, true);
}
this.batchFetchProfiles(uniqueAuthors, { forceRefresh: true });
}
getCurrentUserNpub() {
@@ -2661,9 +2659,10 @@ class Application {
return this.authService.fetchAndRenderProfile(pubkey, forceRefresh);
}
async batchFetchProfiles(authorSet) {
async batchFetchProfiles(authorSet, { forceRefresh = false } = {}) {
return batchFetchProfilesFromRelays({
authorSet,
forceRefresh,
getProfileCacheEntry: (pubkey) => this.getProfileCacheEntry(pubkey),
setProfileCacheEntry: (pubkey, profile) =>
this.setProfileCacheEntry(pubkey, profile),
+4
View File
@@ -10,6 +10,7 @@ const DEFAULT_PROFILE_IMAGE = "assets/svg/default-profile.svg";
export async function batchFetchProfilesFromRelays({
authorSet,
forceRefresh = false,
getProfileCacheEntry,
setProfileCacheEntry,
updateProfileInDOM,
@@ -50,6 +51,9 @@ export async function batchFetchProfilesFromRelays({
const cacheEntry = getProfileCacheEntry(normalizedPubkey);
if (cacheEntry) {
updateProfileInDOM(normalizedPubkey, cacheEntry.profile);
if (forceRefresh) {
toFetch.push(normalizedPubkey);
}
} else {
toFetch.push(normalizedPubkey);
}
+76
View File
@@ -133,3 +133,79 @@ test("batchFetchProfiles handles fast and failing relays", async () => {
{ pubkey: VALID_PUBKEY, profile: { name: "Fast", picture: "fast.png" } },
]);
});
test("batchFetchProfiles respects forceRefresh", async () => {
const cache = new Map();
const updates = [];
const setCalls = [];
const authorSet = new Set([
CACHED_PUBKEY,
]);
const getProfileCacheEntry = (pubkey) => {
if (pubkey === CACHED_PUBKEY) {
return { profile: { name: "Cached", picture: "cached.png" } };
}
return null;
};
const setProfileCacheEntry = (pubkey, profile) => {
cache.set(pubkey, { profile });
setCalls.push({ pubkey, profile });
};
const updateProfileInDOM = (pubkey, profile) => {
updates.push({ pubkey, profile });
};
const originalPool = nostrClient.pool;
const poolListCalls = [];
nostrClient.pool = {
list: (relays, filters) => {
poolListCalls.push({ relays, filters });
return Promise.resolve([
createProfileEvent({
pubkey: CACHED_PUBKEY,
createdAt: 300,
content: { name: "Refreshed", picture: "refreshed.png" },
}),
]);
},
};
try {
await batchFetchProfilesFromRelays({
authorSet,
forceRefresh: true,
getProfileCacheEntry,
setProfileCacheEntry,
updateProfileInDOM,
});
} finally {
nostrClient.pool = originalPool;
}
// Should fetch despite cache presence
assert.ok(poolListCalls.length > 0, "should query relays when forceRefresh is true");
assert.deepEqual(
poolListCalls[0].filters[0].authors,
[CACHED_PUBKEY],
"should include cached pubkey in fetch list"
);
// Should still optimistic update from cache first
assert.deepEqual(
updates[0],
{ pubkey: CACHED_PUBKEY, profile: { name: "Cached", picture: "cached.png" } },
"cached profiles should hydrate immediately even with forceRefresh"
);
// Then update with fresh data
const lastUpdate = updates[updates.length - 1];
assert.deepEqual(
lastUpdate,
{ pubkey: CACHED_PUBKEY, profile: { name: "Refreshed", picture: "refreshed.png" } },
"should update with refreshed data"
);
});