perf(board): reduce desktop reverse-scroll jank on /all

Apply the asymmetric viewport buffer that already fixed mobile to desktop
multiboard feeds, and trim per-post mount cost so remounts during scroll-up
are cheaper:

- Desktop multiboard buffer goes from {600,600} to {1200,2400} (top-heavy),
  matching the mobile pattern from 99c0bbfac so items stay mounted longer
  when scrolling back up
- Cache feed post height estimate by CID in pretext-height-estimates so
  remounts skip the Pretext text-measurement work
- Memoize CommentMedia and switch its expanded-media-store reads to atomic
  selectors so it stops rerendering on unrelated store changes
- Memoize useCommentMediaInfo return so its reference is stable for memo
  comparators downstream
- Stop useFetchGifFirstFrame from forcing an extra render on every post
  mount by bailing out of equivalent setState calls
- Extract PendingModerationActions out of PostInfo so the two
  usePublishCommentModeration calls only run on the post page when
  mod-approval is actually pending, not on every feed item
This commit is contained in:
Tommaso Casaburi
2026-04-18 13:31:02 +07:00
parent d07f5b3962
commit e161606147
8 changed files with 228 additions and 142 deletions
+44 -2
View File
@@ -139,6 +139,8 @@ const paragraphFloatHeightCache = new WeakMap<PreparedTextWithSegments, Map<stri
const nestedPretextElementCache = new WeakMap<HTMLElement, HTMLElement | null>();
const catalogPostHeightEstimateCache = new Map<string, number>();
const catalogRowHeightEstimateCache = new Map<string, number>();
const feedPostHeightEstimateCache = new Map<string, number>();
const FEED_POST_HEIGHT_ESTIMATE_CACHE_LIMIT = 2000;
let pretextSupport: boolean | undefined;
@@ -646,6 +648,30 @@ export const getFeedPostHeightEstimate = ({
const previewRepliesHeight = previewHeights.reduce((sum, value) => sum + value, 0);
const previewReplyCount = previewReplies.length;
const cacheKey = post.cid
? [
isMobile ? '1' : '0',
windowWidth,
showBoardLabel ? '1' : '0',
showSummary ? '1' : '0',
metrics.bodyFontFamily,
metrics.bodyFontSizePx,
metrics.mobileContentFontSizePx,
metrics.abbrFontSizePx,
post.cid,
post.updatedAt || 0,
previewReplyCount,
previewRepliesHeight,
].join('\u0000')
: undefined;
if (cacheKey) {
const cached = feedPostHeightEstimateCache.get(cacheKey);
if (cached !== undefined) {
return cached;
}
}
if (isMobile) {
const fontSizePx = metrics.mobileContentFontSizePx;
const font = `${fontSizePx}px ${metrics.bodyFontFamily}`;
@@ -666,7 +692,15 @@ export const getFeedPostHeightEstimate = ({
// Mobile board cards render preview replies more compactly than the thread-reply estimator assumes.
const mobileCalibration = getMobileFeedCardCalibration(previewReplyCount);
return clampEstimateHeight(rawEstimate - mobileCalibration);
const mobileResult = clampEstimateHeight(rawEstimate - mobileCalibration);
if (cacheKey) {
if (feedPostHeightEstimateCache.size >= FEED_POST_HEIGHT_ESTIMATE_CACHE_LIMIT) {
const firstKey = feedPostHeightEstimateCache.keys().next().value;
if (firstKey !== undefined) feedPostHeightEstimateCache.delete(firstKey);
}
feedPostHeightEstimateCache.set(cacheKey, mobileResult);
}
return mobileResult;
}
const fontSizePx = metrics.bodyFontSizePx;
@@ -698,7 +732,15 @@ export const getFeedPostHeightEstimate = ({
(showSummary ? DESKTOP_FEED_CARD_SUMMARY_HEIGHT : 0) +
previewRepliesHeight;
return clampEstimateHeight(rawEstimate + DESKTOP_FEED_CARD_BASE_CALIBRATION);
const desktopResult = clampEstimateHeight(rawEstimate + DESKTOP_FEED_CARD_BASE_CALIBRATION);
if (cacheKey) {
if (feedPostHeightEstimateCache.size >= FEED_POST_HEIGHT_ESTIMATE_CACHE_LIMIT) {
const firstKey = feedPostHeightEstimateCache.keys().next().value;
if (firstKey !== undefined) feedPostHeightEstimateCache.delete(firstKey);
}
feedPostHeightEstimateCache.set(cacheKey, desktopResult);
}
return desktopResult;
};
export const getCatalogPostHeightEstimate = ({ imageSize, metrics, post, showOPComment }: CatalogPostHeightEstimateOptions): number => {