后端一次性返回 10萬 條數(shù)據(jù)的幾 種應(yīng)對(duì)方案
面試官:后端一次性返回
10萬條
數(shù)據(jù)給你,如何處理?我:歪嘴一笑,
what the f**k!
考察前端如何處理大量數(shù)據(jù)
考察候選人對(duì)于大量數(shù)據(jù)的性能優(yōu)化
問題描述
問題考察點(diǎn)
看似無厘頭的問題,實(shí)際上考查候選人「知識(shí)的廣度和深度」,雖然在工作中這種情況很少遇到...
使用express創(chuàng)建一個(gè)十萬條數(shù)據(jù)的接口
點(diǎn)擊按鈕,發(fā)請(qǐng)求,獲取數(shù)據(jù),渲染到表格上
html結(jié)構(gòu)如下:
方案一: 直接渲染所有數(shù)據(jù)
如果請(qǐng)求到10萬條數(shù)據(jù)直接渲染,頁面會(huì)卡死的,很顯然,這種方式是不可取的
方案二: 使用定時(shí)器分組分批分堆
依次渲染(定時(shí)加載、分堆思想)
正常來說,十萬條數(shù)據(jù)請(qǐng)求,需要2秒到10秒之間(有可能更長,取決于數(shù)據(jù)具體內(nèi)容)
而這種方式就是,前端請(qǐng)求到10萬條數(shù)據(jù)以后,先不著急渲染,先將10萬條數(shù)據(jù)分堆分批次
比如一堆存放10條數(shù)據(jù),那么十萬條數(shù)據(jù)就有一萬堆
使用定時(shí)器,一次渲染一堆,渲染一萬次即可
這樣做的話,頁面就不會(huì)卡死了
分組分批分堆函數(shù)
我們先寫一個(gè)函數(shù),用于將10萬條數(shù)據(jù)進(jìn)行分堆
所謂的分堆其實(shí)「思想就是一次截取一定長度的數(shù)據(jù)」
比如一次截取10條數(shù)據(jù),
頭一次截取0~9,第二次截取10~19等固定長度的截取
舉例原來的數(shù)據(jù)是:
[1,2,3,4,5,6,7]
假設(shè)我們分堆以后,一堆分3個(gè),那么得到的結(jié)果就是二維數(shù)組了
即:
[ [1,2,3], [4,5,6], [7]]
然后就遍歷這個(gè)二維數(shù)組,得到每一項(xiàng)的數(shù)據(jù),即為每一堆的數(shù)據(jù)
進(jìn)而使用定時(shí)器一點(diǎn)點(diǎn)、一堆堆賦值渲染即可
分組分批分堆函數(shù)(一堆分10個(gè))
創(chuàng)建定時(shí)器去依次賦值渲染
比如我們每隔一秒鐘去賦值渲染一次
這種方式,相當(dāng)于在很短的時(shí)間內(nèi)創(chuàng)建許多個(gè)定時(shí)任務(wù)去處理,定時(shí)任務(wù)太多了,也耗費(fèi)資源啊。
實(shí)際上,這種方式就有了大數(shù)據(jù)量分頁的思想
方案三: 使用requestAnimationFrame替代定時(shí)器去做渲染
如果使用請(qǐng)求動(dòng)畫幀的話,就要修改一下代碼寫法了,前面的不變化,plan方法中的寫法變一下即可,注意注釋:
方案四: 搭配分頁組件,前端進(jìn)行分頁(每頁展示一堆,分堆思想)
這種方式,筆者曾經(jīng)遇到過,當(dāng)時(shí)的對(duì)應(yīng)場景是數(shù)據(jù)量也就幾十條,后端直接把幾十條數(shù)據(jù)丟給前端,讓前端去分頁
后端不做分頁的原因是。他當(dāng)時(shí)臨時(shí)有事情請(qǐng)假了,所以就前端去做分頁了。
數(shù)據(jù)量大的情況下,這種方式,也是一種解決方案
思路也是在所有數(shù)據(jù)的基礎(chǔ)上進(jìn)行截取
簡要代碼如下:
方案五: 表格滾動(dòng)觸底加載(滾動(dòng)到底,再加載一堆)
這里重點(diǎn)就是我們需要去判斷,何時(shí)滾動(dòng)條觸底。判斷方式主要有兩種
scrollTop + clientHeight >= innerHeight
或
new MutationObserver()
去觀測
目前市面上主流的一些插件的原理,大致是這兩種。
筆者舉例的這是,是使用的插件v-el-table-infinite-scroll
,本質(zhì)上這個(gè)插件是一個(gè)自定義指令。對(duì)應(yīng)npm
地址:www.npmjs.com/package/el-…
當(dāng)然也有別的插件,如vue-scroller?等:一個(gè)意思,不贅述
注意,觸底加載也是要分堆的,將發(fā)請(qǐng)求獲取到的十萬條數(shù)據(jù),進(jìn)行分好堆,然后每觸底一次,就加載一堆即可
在el-table中使用el-table-infinite-scroll指令步驟
安裝,注意版本號(hào)(區(qū)分vue2和vue3)
「cnpm install \--save el-table-infinite-scroll@1.0.10
」
注冊(cè)使用指令插件
因?yàn)槭且粋€(gè)自定義指令,所以直接寫在el-table
標(biāo)簽上即可
案例代碼
為了方便大家演示,這里筆者直接附上一個(gè)案例代碼,注意看其中的「步驟」注釋即可
方案六: 使用無限加載/虛擬列表進(jìn)行展示
什么是虛擬列表?
所謂的虛擬列表實(shí)際上是「前端障眼法」的一種表現(xiàn)形式。
看到的好像所有的數(shù)據(jù)都渲染了,實(shí)際上只渲染「可視區(qū)域」的部分罷了
有點(diǎn)像我們看電影,我們看的話,是在一塊電影屏幕上,一秒一秒的看(不停的放映)
但是實(shí)際上電影有倆小時(shí),如果把兩個(gè)小時(shí)的電影都鋪開的話,那得需要多少塊電影屏幕呢?
同理,如果10萬條數(shù)據(jù)都渲染,那得需要多少dom節(jié)點(diǎn)元素呢?
所以我們只給用戶看,他「當(dāng)下能看到的」
如果用戶要快進(jìn)或快退(下拉滾動(dòng)條或者上拉滾動(dòng)條)
再把對(duì)應(yīng)的內(nèi)容呈現(xiàn)在電影屏幕上(呈現(xiàn)在可視區(qū)域內(nèi))
這樣就實(shí)現(xiàn)了看著像是所有的dom元素每一條數(shù)據(jù)都有渲染的障眼法效果了
寫一個(gè)簡單的虛擬列表
這里筆者直接上代碼,大家復(fù)制粘貼即可使用,筆者寫了一些注釋,以便于大家理解。
使用vxetable插件實(shí)現(xiàn)虛擬列表
如果不是列表,是table表格的話,筆者這里推薦一個(gè)好用的UI組件,vxetable,看名字就知道做的是表格相關(guān)的業(yè)務(wù)。其中就包括虛擬列表。
vue2
和vue3
版本都支持,性能比較好,官方說:**虛擬滾動(dòng)(最大可以支撐 5w 列、30w 行)
**
強(qiáng)大!
官方網(wǎng)站地址:vxetable.cn/v3/#/table/…
安裝使用代碼
注意安裝版本,筆者使用的版本如下:
cnpm i xe-utils vxe-table@3.6.11 \--save
「main.js」
代碼方面也很簡單,如下:
方案七: 開啟多線程Web Worker進(jìn)行操作
本案例中,使用Web Worker另外開啟一個(gè)線程去操作代碼邏輯,收益并不是特別大(假如使用虛擬滾動(dòng)列表插件的情況下)
不過也算是一個(gè)拓展的思路吧,面試的時(shí)候,倒是可以說一說,提一提。