欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

大量數據場景用虛擬列表還是時間分片?

freeflydom
2024年8月6日 15:14 本文熱度 1253

前言

最近在做一個官網,原本接口做的都是分頁的,但是客戶提出不要分頁,之前看過虛擬列表這個東西,所以進行一下了解。

為啥要用虛擬列表呢!

  在日常工作中,所要渲染的也不單單只是一個li那么簡單,會有很多嵌套在里面。但數據量過多,同時渲染式,會在 渲染樣式 跟 布局計算上花費太多時間,體驗感不好,那你說要不要優化嘛,不是你被優化就是你優化它。

進入正題,啥是虛擬列表?

可以這么理解,根據你視圖能顯示多少就先渲染多少,對看不到的地方采取不渲染或者部分渲染。


這時候你完成首次加載,那么其他就是在你滑動時渲染,就可以通過計算,得知此時屏幕應該顯示的列表項。

怎么弄?

備注:很多方案對于動態不固定高度、網絡圖片以及用戶異常操作等形式處理的也并不好,了解下原理即可。

虛擬列表的實現,實際上就是在首屏加載的時候,只加載可視區域內需要的列表項,當滾動發生時,動態通過計算獲得可視區域內的列表項,并將非可視區域內存在的列表項刪除。

1、計算當前可視區域起始數據索引(startIndex)
2、計算當前可視區域結束數據索引(endIndex)
3、計算當前可視區域的數據,并渲染到頁面中
4、計算startIndex對應的數據在整個列表中的偏移位置startOffset并設置到列表上

  由于只是對可視區域內的列表項進行渲染,所以為了保持列表容器的高度并可正常的觸發滾動,將Html結構設計成如下結構:

<div class="infinite-list-container">

    <div class="infinite-list-phantom"></div>

    <div class="infinite-list">

      <!-- item-1 -->

      <!-- item-2 -->

      <!-- ...... -->

      <!-- item-n -->

    </div>

</div>

  • infinite-list-container 為可視區域的容器

  • infinite-list-phantom 為容器內的占位,高度為總列表高度,用于形成滾動條

  • infinite-list 為列表項的渲染區域

    接著,監聽infinite-list-containerscroll事件,獲取滾動位置scrollTop

  • 假定可視區域高度固定,稱之為screenHeight

  • 假定列表每項高度固定,稱之為itemSize

  • 假定列表數據稱之為listData

  • 假定當前滾動位置稱之為scrollTop

  則可推算出:

  • 列表總高度listHeight = listData.length * itemSize

  • 可顯示的列表項數visibleCount = Math.ceil(screenHeight / itemSize)

  • 數據的起始索引startIndex = Math.floor(scrollTop / itemSize)

  • 數據的結束索引endIndex = startIndex + visibleCount

  • 列表顯示數據為visibleData = listData.slice(startIndex,endIndex)

  當滾動后,由于渲染區域相對于可視區域已經發生了偏移,此時我需要獲取一個偏移量startOffset,通過樣式控制將渲染區域偏移至可視區域中。

  • 偏移量startOffset = scrollTop - (scrollTop % itemSize);

時間分片

那么虛擬列表是一方面可以優化的方式,另一個就是時間分片。

先看看我們平時的情況

1.直接開整,直接渲染。


誒???我們可以發現,js運行時間為113ms,但最終 完成時間是 1070ms,一共是 js 運行時間加上渲染總時間。
PS:

  • 在 JS 的 EventLoop中,當JS引擎所管理的執行棧中的事件以及所有微任務事件全部執行完后,才會觸發渲染線程對頁面進行渲染

  • 第一個 console.log的觸發時間是在頁面進行渲染之前,此時得到的間隔時間為JS運行所需要的時間

  • 第二個 console.log是放到 setTimeout 中的,它的觸發時間是在渲染完成,在下一次 EventLoop中執行的

那我們改用定時器

上面看是因為我們同時渲染,那我們可以分批看看。

let once = 20

  let ul = document.getElementById('testTime')

  function loopRender (curTotal, curIndex) {

    if (curTotal <= 0) return

    let pageCount = Math.min(curTotal, once) // 每頁最多20條

    setTimeout(_ => {

      for (let i=0; i<pageCount;i++) {

        let li = document.createElement('li')

        li.innerHTML = curIndex + i

        ul.appendChild(li)

      }

      loopRender(curTotal - pageCount, curIndex + pageCount)

    }, 0)

  }

  loopRender(100000, 0)

這時候可以感覺出來渲染很快,但是如果渲染復雜點的dom會閃屏,為什么會閃屏這就需要清楚電腦刷新的概念了,這里就不詳細寫了,有興趣的小朋友可以自己去了解一下。
可以改用 requestAnimationFrame 去分批渲染,因為這個關于電腦自身刷新效率的,不管你代碼的事,可以解決丟幀問題。

let once = 20

  let ul = document.getElementById('container')

  // 循環加載渲染數據

  function loopRender (curTotal, curIndex) {

    if (curTotal <= 0) return

    let pageCount = Math.min(curTotal, once) // 每頁最多20條

    window.requestAnimationFrame(_ => {

      for (let i=0; i<pageCount;i++) {

        let li = document.createElement('li')

        li.innerHTML = curIndex + i

        ul.appendChild(li)

      }

      loopRender(curTotal - pageCount, curIndex + pageCount)

    })

  }

  loopRender(100000, 0)

還可以改用 DocumentFragment

什么是 DocumentFragment

DocumentFragment,文檔片段接口,表示一個沒有父級文件的最小文檔對象。它被作為一個輕量版的 Document使用,用于存儲已排好版的或尚未打理好格式的XML片段。最大的區別是因為 DocumentFragment不是真實DOM樹的一部分,它的變化不會觸發DOM樹的(重新渲染) ,且不會導致性能等問題。
可以使用 document.createDocumentFragment方法或者構造函數來創建一個空的 DocumentFragment
ocumentFragments是DOM節點,但并不是DOM樹的一部分,可以認為是存在內存中的,所以將子元素插入到文檔片段時不會引起頁面回流。

  當 append元素到 document中時,被 append進去的元素的樣式表的計算是同步發生的,此時調用 getComputedStyle 可以得到樣式的計算值。而 append元素到 documentFragment 中時,是不會計算元素的樣式表,所以 documentFragment 性能更優。當然現在瀏覽器的優化已經做的很好了, 當 append元素到 document中后,沒有訪問 getComputedStyle 之類的方法時,現代瀏覽器也可以把樣式表的計算推遲到腳本執行之后。

let once = 20 

  let ul = document.getElementById('container')

  // 循環加載渲染數據

  function loopRender (curTotal, curIndex) {

    if (curTotal <= 0) return

    let pageCount = Math.min(curTotal, once) // 每頁最多20條

    window.requestAnimationFrame(_ => {

      let fragment = document.createDocumentFragment()

      for (let i=0; i<pageCount;i++) {

        let li = document.createElement('li')

        li.innerHTML = curIndex + i

        fragment.appendChild(li)

      }

      ul.appendChild(fragment)

      loopRender(curTotal - pageCount, curIndex + pageCount)

    })

  }

  loopRender(100000, 0)

其實同時渲染十萬條數據這個情況還是比較少見的,就當做個了解吧。


該文章在 2024/8/6 15:16:03 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved