如何順滑的展示大資料列表?

上線前夕發表於2020-06-19

每每談到前端效能優化,大資料列表的呈現總是一個老生常談的話題。基於瀏覽器本身處理DOM的方式,一旦列表資料足夠大時,總是不可避免的出現CUP和記憶體佔用導致的卡頓問題,因此,針對大資料列表,只能使用特別的方式來呈現。

面對這個問題時,直覺反應就是切分:切成小塊再呈現。比如,現在有10萬條資料,僅僅拿出前1000條呈現出來,隨著滾動條的滑動再逐步展示後面資料。然而,這種方式引起的列表高度變化會給使用者帶來非常糟糕的滑動體驗,無論是補充資料還是把原列表換掉,使用起來跟標準滾動條差別非常大。因此,僅僅是切分還遠遠不夠。

定高

為了防止列表高度變化帶來的滾動體驗問題,需要在大列表呈現時就先計算好高度。也就是說當要呈現10萬條資料時,即使只先呈現前1000條,10W條資料的總高度要先被算好並設定在最外層的容器上。目的是當滑動時,呈現的資料變化,但容器總高度不變,這樣體驗起來才會和普通滾動條一致。

給10萬條資料定高,就意味著你需要知道每一條資料呈現出來的高度是多少,在程式碼實現層面,可以拿出其中一條資料展示出來獲取其高度。如此一來,不但總容器的高度能確定,每一條資料在縱座標的起始位置也能定下,為後續的滑動展示提供基礎。

通過單項定高

分組

一旦高度定下,就可以根據滾動條的的位置展示或隱藏列表資料,但具體的程式碼實現卻不得不考慮效能問題,因為需要遍歷整個列表逐個判斷,10W條資料遍歷一次也是特別大的運算,更糟糕的是,滾動條滑動的事件觸發是非常頻繁的。

解決方案就是分組,即將100個或1000個劃分為一組,以組為單位進行判斷,同時,需要在定高時根據每一項高度計算出組的縱座標起始位置。如此一來,遍歷時以組為單位大大減少了計算量,10W條資料,1000個為1組,遍歷起來也就只有100組而已。

分組後,滑動展示時便可以靈活制定展示規則,比如滾動條劃過當前組高度一大半以後展示下一組等。

分組後的滑動展示預覽圖

分組演算法

因為看了國外一篇寫大資料列表的文章有感,才寫了此文。值得一提的是,那篇文章中的分組方式很特別,利用二叉樹演算法,一個簡潔遞迴就把資料分好了。

recursiveSplit =(data)=> {
    if(data.length / 2 > this.minimumStackSize) {
      let mid = Math.floor(data.length/2, 10);
      let node = { 
        parent: true,
        getParent: ()=> data,
        data: [this.recursiveSplit(data.slice(0, mid)), this.recursiveSplit(data.slice(mid, data.length+1))]
      }
      return node;
    }
    return {
      parent: false,
      data
    }
  }

作者最終Demo的效果如圖,相關連結我已貼在文章底部。

demo效果展示圖

結語

處理大資料列表的呈現,關鍵點有兩個,一是定高,二是分組。定高保證了選擇性呈現資料時滾動條的正常體驗,分組則處理了頻繁遍歷帶來的效能消耗。

參考資料:

https://medium.com/better-pro...

https://react-eternal-list.ri...

https://github.com/rinasm/rea...

相關文章