跳至主要內容
科技 科技評論

120張圖只加載出4張:懶加載防抖方案的實測帳,算的是工程時間的浪費

開發者實測九種圖片懶加載寫法,防抖方案在120張圖的長列表中僅加載4張,本文從前端工程成本與瀏覽器原生功能替代曲線拆解這組數據。

刊登 閱讀約 5 分鐘

2026年10月27日,掘金平臺上一位署名 kyriewen 的開發者發布了一篇實測文章。起因很單純:他為圖庫頁更換懶加載方案,搜尋教學時發現各篇教程互斥、彼此看不上,於是決定把九種寫法放進同一張120張圖的頁面,全部跑一遍。

結果裡有一個數字值得單獨列出:其中一種寫法,120張圖滾到底只加載出4張,其餘116張從頭到尾沒有發起過請求。而這個寫法在各種教程中的出現頻率還不低。

實驗條件與方法

先把量測口徑交代清楚。測試頁面為120張圖,每張67KB,本地服務、禁用快取。每張圖從「進入視口」到「加載完成」的延遲逐張記錄,服務端同步記錄請求時間戳。滾動方式統一為每幀24像素、一口氣滾到底,模擬用戶快速刷長列表的行為。每種寫法跑三輪,三輪數據差距不到1毫秒。

九種寫法涵蓋:不做懶加載、原生 loading=“lazy”、原生加 fetchpriority=low、IntersectionObserver 三檔預載距離(0px/200px/1000px)、裸 scroll 監聽、scroll 加 requestAnimationFrame 合幀、scroll 加 250ms 防抖。

防抖為何翻車:一個機制問題

防抖方案的就位延遲中位數是615ms,看起來只是慢。真正的問題在加載數量:整輪滾動結束只有4張圖完成請求。

機制不複雜。防抖的定義是每次事件觸發就重置定時器,用戶只要還在滾動,scroll 事件就持續到來,250ms 的定時器被不斷推倒重來,加載檢查一次都沒執行。等用戶滾到底停下來,檢查才終於跑了一次,但視口裡只剩最後幾張圖。

作為對照,scroll 加 requestAnimationFrame 合幀的方案,就位延遲是14ms。同一臺機器、同一批圖片,唯一差別是那個250ms定時器,兩者相差約44倍。作者用了一個比喻:這等於把外送員防抖了,你越催他越不動,等你餓死了他才拎著飯出門。

原生屬性與手寫方案的替代帳

不寫防抖的手寫方案成績都正常,但對比數據指向另一件事。

Chrome 官方口徑中,原生 loading=“lazy” 的預載距離約1250px。實測數據吻合:原生寫法的圖片平均提前851ms就緒。而手寫 IntersectionObserver 的教程,多數教 rootMargin: 200px,這個配置實測只提前119ms。要追平原生表現,預載距離得拉到1000px,實測提前685ms。

換句話說,手寫二十行 JavaScript 維護一個 IntersectionObserver,用戶反而比瀏覽器自帶的一行屬性多等約半秒。從工程成本角度,這是多花的人力維護一個表現更差的替代品,屬於典型的替代曲線錯位:原生功能已經越過手寫方案的性能水平時,手寫的理由只剩相容性需求。

作者順帶澄清了兩個流傳的說法。其一,fetchpriority=low 能優化懶加載:實測數據與不加逐項相同,這個屬性是給首屏大圖搶 bandwidth 用的。其二,裸 scroll 監聽會卡:在120張圖的規模下,九種寫法幀率中位全部為17ms,長任務零次。裸監聽全量呼叫 getBoundingClientRect 並不卡,真正的缺點是就位延遲比 IO 方案慢一倍。

懶加載省的到底是什麼

看首屏請求那一欄,帳就清楚了。不做懶加載的頁面,打開瞬間搶下全部120張圖的請求;懶加載方案則只拿1到7張。以每張67KB計,120張全量載入約8MB出頭,懶加載把首屏流量壓到數百KB等級。

它省的是流量與伺服器頻寬帳單,並非幀率。這個區分對成本歸屬有實際意義:內容型網站的圖片流量直接計入 CDN 與頻寬支出,懶加載的收益記在這一欄,而不是用戶體驗的流暢度欄位。

數據的邊界

作者自己標明了實驗限制。headless Chrome 的幀率數據在真機上未必能重現,這一點他不爭辯。但防抖翻車是機制問題,預載距離是瀏覽器行為,這兩項結論與運行環境無關。

至於防抖方案是否只是湊數的對照組,作者指出這個場景一點都不罕見:長列表快刷、錨點跳轉、按一下 End 鍵,全都是一口氣滾到底的操作。防抖懶加載在慢速瀏覽時能勉強過關,測試案例稍微慢一點它就隱身,一旦用戶滾快了就直接失效。這也是它長期沒被發現的原因:失效條件恰好落在常規測試路徑之外。

結論帳

這份實測給出的工程結算很直接:程式碼庫裡若有 scroll 加 debounce 的懶加載,不值得修,直接刪。手寫 IntersectionObserver 若要保留,rootMargin 至少拉到1000px 才有與原生屬性可比的表現。而對多數場景,原生 loading=“lazy” 一行屬性已經在預載距離與就位延遲兩項指標上勝過大部分手寫教程的預設配置。

一篇個人實測文章能流傳,反映的是教程內容長期缺乏可驗證基準的現狀。當「哪種寫法最好」的爭論沒有數據仲裁時,一組120張圖、27輪滾動的對照表,比九篇互相否定的教程加起來更有參考價值。