狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

大量數(shù)據(jù)場(chǎng)景用虛擬列表還是時(shí)間分片?

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

前言

最近在做一個(gè)官網(wǎng),原本接口做的都是分頁(yè)的,但是客戶提出不要分頁(yè),之前看過(guò)虛擬列表這個(gè)東西,所以進(jìn)行一下了解。

為啥要用虛擬列表呢!

  在日常工作中,所要渲染的也不單單只是一個(gè)li那么簡(jiǎn)單,會(huì)有很多嵌套在里面。但數(shù)據(jù)量過(guò)多,同時(shí)渲染式,會(huì)在 渲染樣式 跟 布局計(jì)算上花費(fèi)太多時(shí)間,體驗(yàn)感不好,那你說(shuō)要不要優(yōu)化嘛,不是你被優(yōu)化就是你優(yōu)化它。

進(jìn)入正題,啥是虛擬列表?

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


這時(shí)候你完成首次加載,那么其他就是在你滑動(dòng)時(shí)渲染,就可以通過(guò)計(jì)算,得知此時(shí)屏幕應(yīng)該顯示的列表項(xiàng)。

怎么弄?

備注:很多方案對(duì)于動(dòng)態(tài)不固定高度、網(wǎng)絡(luò)圖片以及用戶異常操作等形式處理的也并不好,了解下原理即可。

虛擬列表的實(shí)現(xiàn),實(shí)際上就是在首屏加載的時(shí)候,只加載可視區(qū)域內(nèi)需要的列表項(xiàng),當(dāng)滾動(dòng)發(fā)生時(shí),動(dòng)態(tài)通過(guò)計(jì)算獲得可視區(qū)域內(nèi)的列表項(xiàng),并將非可視區(qū)域內(nèi)存在的列表項(xiàng)刪除。

1、計(jì)算當(dāng)前可視區(qū)域起始數(shù)據(jù)索引(startIndex)
2、計(jì)算當(dāng)前可視區(qū)域結(jié)束數(shù)據(jù)索引(endIndex)
3、計(jì)算當(dāng)前可視區(qū)域的數(shù)據(jù),并渲染到頁(yè)面中
4、計(jì)算startIndex對(duì)應(yīng)的數(shù)據(jù)在整個(gè)列表中的偏移位置startOffset并設(shè)置到列表上

  由于只是對(duì)可視區(qū)域內(nèi)的列表項(xiàng)進(jìn)行渲染,所以為了保持列表容器的高度并可正常的觸發(fā)滾動(dòng),將Html結(jié)構(gòu)設(shè)計(jì)成如下結(jié)構(gòu):

<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 為可視區(qū)域的容器

  • infinite-list-phantom 為容器內(nèi)的占位,高度為總列表高度,用于形成滾動(dòng)條

  • infinite-list 為列表項(xiàng)的渲染區(qū)域

    接著,監(jiān)聽(tīng)infinite-list-containerscroll事件,獲取滾動(dòng)位置scrollTop

  • 假定可視區(qū)域高度固定,稱之為screenHeight

  • 假定列表每項(xiàng)高度固定,稱之為itemSize

  • 假定列表數(shù)據(jù)稱之為listData

  • 假定當(dāng)前滾動(dòng)位置稱之為scrollTop

  則可推算出:

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

  • 可顯示的列表項(xiàng)數(shù)visibleCount = Math.ceil(screenHeight / itemSize)

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

  • 數(shù)據(jù)的結(jié)束索引endIndex = startIndex + visibleCount

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

  當(dāng)滾動(dòng)后,由于渲染區(qū)域相對(duì)于可視區(qū)域已經(jīng)發(fā)生了偏移,此時(shí)我需要獲取一個(gè)偏移量startOffset,通過(guò)樣式控制將渲染區(qū)域偏移至可視區(qū)域中。

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

時(shí)間分片

那么虛擬列表是一方面可以優(yōu)化的方式,另一個(gè)就是時(shí)間分片。

先看看我們平時(shí)的情況

1.直接開(kāi)整,直接渲染。


誒???我們可以發(fā)現(xiàn),js運(yùn)行時(shí)間為113ms,但最終 完成時(shí)間是 1070ms,一共是 js 運(yùn)行時(shí)間加上渲染總時(shí)間。
PS:

  • 在 JS 的 EventLoop中,當(dāng)JS引擎所管理的執(zhí)行棧中的事件以及所有微任務(wù)事件全部執(zhí)行完后,才會(huì)觸發(fā)渲染線程對(duì)頁(yè)面進(jìn)行渲染

  • 第一個(gè) console.log的觸發(fā)時(shí)間是在頁(yè)面進(jìn)行渲染之前,此時(shí)得到的間隔時(shí)間為JS運(yùn)行所需要的時(shí)間

  • 第二個(gè) console.log是放到 setTimeout 中的,它的觸發(fā)時(shí)間是在渲染完成,在下一次 EventLoop中執(zhí)行的

那我們改用定時(shí)器

上面看是因?yàn)槲覀兺瑫r(shí)渲染,那我們可以分批看看。

let once = 20

  let ul = document.getElementById('testTime')

  function loopRender (curTotal, curIndex) {

    if (curTotal <= 0) return

    let pageCount = Math.min(curTotal, once) // 每頁(yè)最多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)

這時(shí)候可以感覺(jué)出來(lái)渲染很快,但是如果渲染復(fù)雜點(diǎn)的dom會(huì)閃屏,為什么會(huì)閃屏這就需要清楚電腦刷新的概念了,這里就不詳細(xì)寫(xiě)了,有興趣的小朋友可以自己去了解一下。
可以改用 requestAnimationFrame 去分批渲染,因?yàn)檫@個(gè)關(guān)于電腦自身刷新效率的,不管你代碼的事,可以解決丟幀問(wèn)題。

let once = 20

  let ul = document.getElementById('container')

  // 循環(huán)加載渲染數(shù)據(jù)

  function loopRender (curTotal, curIndex) {

    if (curTotal <= 0) return

    let pageCount = Math.min(curTotal, once) // 每頁(yè)最多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,文檔片段接口,表示一個(gè)沒(méi)有父級(jí)文件的最小文檔對(duì)象。它被作為一個(gè)輕量版的 Document使用,用于存儲(chǔ)已排好版的或尚未打理好格式的XML片段。最大的區(qū)別是因?yàn)?nbsp;DocumentFragment不是真實(shí)DOM樹(shù)的一部分,它的變化不會(huì)觸發(fā)DOM樹(shù)的(重新渲染) ,且不會(huì)導(dǎo)致性能等問(wèn)題。
可以使用 document.createDocumentFragment方法或者構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè)空的 DocumentFragment
ocumentFragments是DOM節(jié)點(diǎn),但并不是DOM樹(shù)的一部分,可以認(rèn)為是存在內(nèi)存中的,所以將子元素插入到文檔片段時(shí)不會(huì)引起頁(yè)面回流。

  當(dāng) append元素到 document中時(shí),被 append進(jìn)去的元素的樣式表的計(jì)算是同步發(fā)生的,此時(shí)調(diào)用 getComputedStyle 可以得到樣式的計(jì)算值。而 append元素到 documentFragment 中時(shí),是不會(huì)計(jì)算元素的樣式表,所以 documentFragment 性能更優(yōu)。當(dāng)然現(xiàn)在瀏覽器的優(yōu)化已經(jīng)做的很好了, 當(dāng) append元素到 document中后,沒(méi)有訪問(wèn) getComputedStyle 之類的方法時(shí),現(xiàn)代瀏覽器也可以把樣式表的計(jì)算推遲到腳本執(zhí)行之后。

let once = 20 

  let ul = document.getElementById('container')

  // 循環(huán)加載渲染數(shù)據(jù)

  function loopRender (curTotal, curIndex) {

    if (curTotal <= 0) return

    let pageCount = Math.min(curTotal, once) // 每頁(yè)最多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)

其實(shí)同時(shí)渲染十萬(wàn)條數(shù)據(jù)這個(gè)情況還是比較少見(jiàn)的,就當(dāng)做個(gè)了解吧。

來(lái)源https://juejin.cn/post/7263009476058742840 作者:NIIBLE


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