長列表優化
, 是頁面性能優化
中的一個比較常見的問題,也是面試中的常客。面試
恰好最近在的項目中, 遇到了一個長列表的性能問題,試過多種方案, 最後得以解決。chrome
今天就給你們分享一下。瀏覽器
用戶須要批量修改 Product中 sku 的 映射關係,能夠選擇的 Product 的 數量不限
。性能優化
每一條sku 對應以下結構:antd
由於能夠選擇的sku數量是不限的, 又不能分頁, 只能作到一個列表裏。dom
因而, 長列表出現了。工具
剛開始的方案是作一個虛擬列表
。性能
具體就是經過監聽sroll事件,每次滾動後計算通常元素位置(top和height)測試
而後,經過渲染三屏的方式,把一段數據渲染到頁面上。優化
數據量很少的時候, 沒什麼問題。
當選擇幾百上千條sku 的時候, 快速滑動, 就開始出現卡頓。
如圖所示:
做爲對比,看一下優化後的效果:
在chrome調試工具下,邊拖動列表邊觀察dom的變化。
發現,dom的卸載/掛載/更新的狀況都出奇地慢,鼠標已經停下來,能明顯感受到過一會dom才裝載完成,因此極可能是dom的渲染性能問題。
定位到渲染性能有問題的dom身上,即每個 Item(renderFakeTable)。
使用普通文本代替Item,在一樣多數量的列表狀況下,簡單的dom明顯會順暢不少,可是,仍然會出現空白問題。
繼續觀察renderFakeTable中的每個元素(能夠借用devTools Profiler)。
最簡單粗暴的方式就是去除某一類的組件,而後經過不斷自測的方式,找出最有可能影響渲染效率的元素:
SearchSelect(基於antd的Select封裝的一個業務組件)。
因此,影響渲染性能的元素極可能就是它。
除了組件的問題,還有多是渲染
的問題。
首先,原來無限滾動的邏輯就是基於scroll事件,經過不斷滾動觸發的回調,從新計算渲染到頁面上的區間。
其次,爲了動態調整可視區域的元素,使用了MutationObserver。
致使空白問題則會有這幾種可能:
不幸運的是,以上的可能都一一排除後,發現幾乎沒有啥提高。
其實,在第二點縮小範圍時,應該意識到,空白問題/拖動不流暢均是由於渲染性能低下
致使的
爲了驗證是Select 組件的問題,基於:
rc-virtual-list
作了一個在線 demo :
在線地址:https://codesandbox.io/s/opti...
動態演示:
這裏渲染了1000 條記錄, 每條記錄裏有5個select;
默認使用的是 antd Select, 幾乎拉不動;
切換到原生select以後, 如絲般順滑。
由此能夠肯定,卡頓是 Slect 組件引發的。
因此要減小渲染成本:
基於 Intersection Observer
實現一個 下拉懶加載。
利用 Intersection Observer 實現:
在列表的底部(也多是底部偏上的某個位置)插入一個observer-dom元素.
經過Observer來觀測其是否在可視區域中,若是在,那麼就往下加載更多的內容:
初始狀態時,列表會多渲染幾條數據(兩屏數據),observer-dom元素一直被頂到底部.
用戶往下滾動時,observer-dom元素「出現」在用戶視野。
每次多加載一屏的數據,循環如此,直到整個列表都渲染到頁面上。
在線demo:
https://codesandbox.io/s/gund...
動態演示:
最終採用下拉懶加載。
一般,無限滾動的方案能夠分爲兩種:
在選擇虛擬長列表or下拉懶加載之間的取捨時,能夠參考:
若是閃動問題能夠接受(組件渲染沒有太大性能問題),並且對dom數量要求很嚴格,那麼選擇虛擬長列表會更好。
若是閃動問題不能接受,而最終的dom數量可以接受,那麼選擇下拉藍加載會更好。
不管是選擇虛擬長列表or下拉懶加載,在使用監聽scroll事件或者Intersetion Observer API之間的取捨時,能夠參考:
而使用Intersetion Observer API,上述幾點的計算就能夠省略了,優化工做交給了瀏覽器。
若是不考慮IE 等, 它是一個不錯的選擇。
內容就這麼多, 但願對你們有所啓發。
若有錯誤, 歡迎指正, 謝謝。