perf(preview): debounce full-res /proxy preload by 400ms
Rapid arrow-nav was firing one /proxy fetch per photo with no way to abort (new Image() has no abort). Holding the right arrow through ten photos in two seconds left ten multi-MB transfers in flight competing for bandwidth and the RAW/HEIC transcoder. Now the preload only kicks in if the user lingers on a photo for 400ms; otherwise the timer is cleared and no /proxy request is made.
This commit is contained in:
@@ -59,21 +59,30 @@ function PreviewStillImage({ photo }: { photo: Photo }) {
|
||||
const fullResSrc = getPreviewFullResSrc(photo)
|
||||
const src = usingFullRes ? fullResSrc : thumbSrc
|
||||
|
||||
// Reset everything when the photo changes, then start the background
|
||||
// full-res preload. Cancel the preloader's callback on unmount/change so a
|
||||
// late-arriving onload from the previous photo can't flip state for the
|
||||
// current one.
|
||||
// Reset everything when the photo changes, then queue a *debounced*
|
||||
// background full-res preload. Debouncing matters because `new Image()`
|
||||
// requests can't be aborted: rapid arrow-nav would otherwise leave a
|
||||
// dozen multi-MB /proxy fetches in flight, saturating the user's
|
||||
// bandwidth (and the backend's transcoder for RAW/HEIC) for photos the
|
||||
// user already navigated past. Only photos the user lingers on for
|
||||
// FULL_RES_PRELOAD_DELAY_MS trigger the /proxy fetch.
|
||||
useEffect(() => {
|
||||
setLoaded(false)
|
||||
setUsingFullRes(false)
|
||||
setScale(1)
|
||||
setOffset({ x: 0, y: 0 })
|
||||
|
||||
const preloader = new Image()
|
||||
preloader.onload = () => setUsingFullRes(true)
|
||||
preloader.src = fullResSrc
|
||||
const FULL_RES_PRELOAD_DELAY_MS = 400
|
||||
let preloader: HTMLImageElement | null = null
|
||||
const timer = window.setTimeout(() => {
|
||||
preloader = new Image()
|
||||
preloader.onload = () => setUsingFullRes(true)
|
||||
preloader.src = fullResSrc
|
||||
}, FULL_RES_PRELOAD_DELAY_MS)
|
||||
|
||||
return () => {
|
||||
preloader.onload = null
|
||||
window.clearTimeout(timer)
|
||||
if (preloader) preloader.onload = null
|
||||
}
|
||||
}, [photo.id, fullResSrc])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user