内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

「前端進(jìn)階」高性能渲染十萬(wàn)條數(shù)據(jù)(時(shí)間分片)-創(chuàng)新互聯(lián)

前言
在實(shí)際工作中,我們很少會(huì)遇到一次性需要向頁(yè)面中插入大量數(shù)據(jù)的情況,但是為了豐富我們的知識(shí)體系,我們有必要了解并清楚當(dāng)遇到大量數(shù)據(jù)時(shí),如何才能在不卡主頁(yè)面的情況下渲染數(shù)據(jù),以及其中背后的原理。

成都創(chuàng)新互聯(lián)是一家網(wǎng)站設(shè)計(jì)公司,集創(chuàng)意、互聯(lián)網(wǎng)應(yīng)用、軟件技術(shù)為一體的創(chuàng)意網(wǎng)站建設(shè)服務(wù)商,主營(yíng)產(chǎn)品:自適應(yīng)網(wǎng)站建設(shè)、品牌網(wǎng)站建設(shè)成都營(yíng)銷網(wǎng)站建設(shè)。我們專注企業(yè)品牌在網(wǎng)站中的整體樹(shù)立,網(wǎng)絡(luò)互動(dòng)的體驗(yàn),以及在手機(jī)等移動(dòng)端的優(yōu)質(zhì)呈現(xiàn)。網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、移動(dòng)互聯(lián)產(chǎn)品、網(wǎng)絡(luò)運(yùn)營(yíng)、VI設(shè)計(jì)、云產(chǎn)品.運(yùn)維為核心業(yè)務(wù)。為用戶提供一站式解決方案,我們深知市場(chǎng)的競(jìng)爭(zhēng)激烈,認(rèn)真對(duì)待每位客戶,為客戶提供賞析悅目的作品,網(wǎng)站的價(jià)值服務(wù)。

對(duì)于一次性插入大量數(shù)據(jù)的情況,一般有兩種做法:

時(shí)間分片
虛擬列表
本文作為開(kāi)篇,著重來(lái)介紹如何使用時(shí)間分片的方式來(lái)渲染大量數(shù)據(jù),虛擬列表相關(guān)的內(nèi)容,日后會(huì)持續(xù)整理。

最粗暴的做法(一次性渲染)
我們先來(lái)看看最粗暴的做法,一次性將大量數(shù)據(jù)插入到頁(yè)面中:

<ul id="container"></ul>
復(fù)制代碼
// 記錄任務(wù)開(kāi)始時(shí)間
let now = Date.now();
// 插入十萬(wàn)條數(shù)據(jù)
const total = 100000;
// 獲取容器
let ul = document.getElementById('container');
// 將數(shù)據(jù)插入容器中
for (let i = 0; i < total; i++) {
let li = document.createElement('li');
li.innerText = ~~(Math.random() * total)
ul.appendChild(li);
}

console.log('JS運(yùn)行時(shí)間:',Date.now() - now);
setTimeout(()=>{
console.log('總運(yùn)行時(shí)間:',Date.now() - now);
},0)
// print: JS運(yùn)行時(shí)間: 187
// print: 總運(yùn)行時(shí)間: 2844
復(fù)制代碼
我們對(duì)十萬(wàn)條記錄進(jìn)行循環(huán)操作,JS的運(yùn)行時(shí)間為187ms,還是蠻快的,但是最終渲染完成后的總時(shí)間確是2844ms。

簡(jiǎn)單說(shuō)明一下,為何兩次console.log的結(jié)果時(shí)間差異巨大,并且是如何簡(jiǎn)單來(lái)統(tǒng)計(jì)JS運(yùn)行時(shí)間和總渲染時(shí)間:

在 JS 的Event Loop中,當(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í)間是在渲染完成,在下一次Event Loop中執(zhí)行的
關(guān)于Event Loop的詳細(xì)內(nèi)容請(qǐng)參見(jiàn)這篇文章-->

依照兩次console.log的結(jié)果,可以得出結(jié)論:

對(duì)于大量數(shù)據(jù)渲染的時(shí)候,JS運(yùn)算并不是性能的瓶頸,性能的瓶頸主要在于渲染階段

使用定時(shí)器
從上面的例子,我們已經(jīng)知道,頁(yè)面的卡頓是由于同時(shí)渲染大量DOM所引起的,所以我們考慮將渲染過(guò)程分批進(jìn)行

在這里,我們使用setTimeout來(lái)實(shí)現(xiàn)分批渲染

<ul id="container"></ul>
復(fù)制代碼
//需要插入的容器
let ul = document.getElementById('container');
// 插入十萬(wàn)條數(shù)據(jù)
let total = 100000;
// 一次插入 20 條
let once = 20;
//總頁(yè)數(shù)
let page = total/once
//每條記錄的索引
let index = 0;
//循環(huán)加載數(shù)據(jù)
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每頁(yè)多少條
let pageCount = Math.min(curTotal , once);
setTimeout(()=>{
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount,curIndex + pageCount)
},0)
}
loop(total,index);
復(fù)制代碼
用一個(gè)gif圖來(lái)看一下效果

我們可以看到,頁(yè)面加載的時(shí)間已經(jīng)非??炝?,每次刷新時(shí)可以很快的看到第一屏的所有數(shù)據(jù),但是當(dāng)我們快速滾動(dòng)頁(yè)面的時(shí)候,會(huì)發(fā)現(xiàn)頁(yè)面出現(xiàn)閃屏或白屏的現(xiàn)象

為什么會(huì)出現(xiàn)閃屏現(xiàn)象呢
首先,理清一些概念。FPS表示的是每秒鐘畫(huà)面更新次數(shù)。我們平時(shí)所看到的連續(xù)畫(huà)面都是由一幅幅靜止畫(huà)面組成的,每幅畫(huà)面稱為一幀,F(xiàn)PS是描述幀變化速度的物理量。

大多數(shù)電腦顯示器的刷新頻率是60Hz,大概相當(dāng)于每秒鐘重繪60次,F(xiàn)PS為60frame/s,為這個(gè)值的設(shè)定受屏幕分辨率、屏幕尺寸和顯卡的影響。

因此,當(dāng)你對(duì)著電腦屏幕什么也不做的情況下,大多顯示器也會(huì)以每秒60次的頻率正在不斷的更新屏幕上的圖像。

為什么你感覺(jué)不到這個(gè)變化?

那是因?yàn)槿说难劬τ幸曈X(jué)停留效應(yīng),即前一副畫(huà)面留在大腦的印象還沒(méi)消失,緊接著后一副畫(huà)面就跟上來(lái)了, 這中間只間隔了16.7ms(1000/60≈16.7),所以會(huì)讓你誤以為屏幕上的圖像是靜止不動(dòng)的。

而屏幕給你的這種感覺(jué)是對(duì)的,試想一下,如果刷新頻率變成1次/秒,屏幕上的圖像就會(huì)出現(xiàn)嚴(yán)重的閃爍, 這樣就很容易引起眼睛疲勞、酸痛和頭暈?zāi)垦5劝Y狀。

大多數(shù)瀏覽器都會(huì)對(duì)重繪操作加以限制,不超過(guò)顯示器的重繪頻率,因?yàn)榧词钩^(guò)那個(gè)頻率用戶體驗(yàn)也不會(huì)有提升。 因此,最平滑動(dòng)畫(huà)的最佳循環(huán)間隔是1000ms/60,約等于16.6ms。

直觀感受,不同幀率的體驗(yàn):

幀率能夠達(dá)到 50 ~ 60 FPS 的動(dòng)畫(huà)將會(huì)相當(dāng)流暢,讓人倍感舒適;
幀率在 30 ~ 50 FPS 之間的動(dòng)畫(huà),因各人敏感程度不同,舒適度因人而異;
幀率在 30 FPS 以下的動(dòng)畫(huà),讓人感覺(jué)到明顯的卡頓和不適感;
幀率波動(dòng)很大的動(dòng)畫(huà),亦會(huì)使人感覺(jué)到卡頓。
簡(jiǎn)單聊一下 setTimeout 和閃屏現(xiàn)象
setTimeout的執(zhí)行時(shí)間并不是確定的。在JS中,setTimeout任務(wù)被放進(jìn)事件隊(duì)列中,只有主線程執(zhí)行完才會(huì)去檢查事件隊(duì)列中的任務(wù)是否需要執(zhí)行,因此setTimeout的實(shí)際執(zhí)行時(shí)間可能會(huì)比其設(shè)定的時(shí)間晚一些。
刷新頻率受屏幕分辨率和屏幕尺寸的影響,因此不同設(shè)備的刷新頻率可能會(huì)不同,而setTimeout只能設(shè)置一個(gè)固定時(shí)間間隔,這個(gè)時(shí)間不一定和屏幕的刷新時(shí)間相同。
以上兩種情況都會(huì)導(dǎo)致setTimeout的執(zhí)行步調(diào)和屏幕的刷新步調(diào)不一致。

在setTimeout中對(duì)dom進(jìn)行操作,必須要等到屏幕下次繪制時(shí)才能更新到屏幕上,如果兩者步調(diào)不一致,就可能導(dǎo)致中間某一幀的操作被跨越過(guò)去,而直接更新下一幀的元素,從而導(dǎo)致丟幀現(xiàn)象。

使用 requestAnimationFrame
與setTimeout相比,requestAnimationFrame大的優(yōu)勢(shì)是由系統(tǒng)來(lái)決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)。

如果屏幕刷新率是60Hz,那么回調(diào)函數(shù)就每16.7ms被執(zhí)行一次,如果刷新率是75Hz,那么這個(gè)時(shí)間間隔就變成了1000/75=13.3ms,換句話說(shuō)就是,requestAnimationFrame的步伐跟著系統(tǒng)的刷新步伐走。它能保證回調(diào)函數(shù)在屏幕每一次的刷新間隔中只被執(zhí)行一次,這樣就不會(huì)引起丟幀現(xiàn)象。

我們使用requestAnimationFrame來(lái)進(jìn)行分批渲染:

<ul id="container"></ul>
復(fù)制代碼
//需要插入的容器
let ul = document.getElementById('container');
// 插入十萬(wàn)條數(shù)據(jù)
let total = 100000;
// 一次插入 20 條
let once = 20;
//總頁(yè)數(shù)
let page = total/once
//每條記錄的索引
let index = 0;
//循環(huán)加載數(shù)據(jù)
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每頁(yè)多少條
let pageCount = Math.min(curTotal , once);
window.requestAnimationFrame(function(){
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount,curIndex + pageCount)
})
}
loop(total,index);
復(fù)制代碼
看下效果

我們可以看到,頁(yè)面加載的速度很快,并且滾動(dòng)的時(shí)候,也很流暢沒(méi)有出現(xiàn)閃爍丟幀的現(xiàn)象。

這就結(jié)束了么,還可以再優(yōu)化么?

當(dāng)然~~

使用 DocumentFragment
先解釋一下什么是 DocumentFragment ,文獻(xiàn)引用自MDN

DocumentFragment,文檔片段接口,表示一個(gè)沒(méi)有父級(jí)文件的最小文檔對(duì)象。它被作為一個(gè)輕量版的Document使用,用于存儲(chǔ)已排好版的或尚未打理好格式的XML片段。大的區(qū)別是因?yàn)镈ocumentFragment不是真實(shí)DOM樹(shù)的一部分,它的變化不會(huì)觸發(fā)DOM樹(shù)的(重新渲染) ,且不會(huì)導(dǎo)致性能等問(wèn)題。
可以使用document.createDocumentFragment方法或者構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè)空的DocumentFragment

從MDN的說(shuō)明中,我們得知DocumentFragments是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í)行之后。

最后修改代碼如下:

<ul id="container"></ul>
復(fù)制代碼
//需要插入的容器
let ul = document.getElementById('container');
// 插入十萬(wàn)條數(shù)據(jù)
let total = 100000;
// 一次插入 20 條
let once = 20;
//總頁(yè)數(shù)
let page = total/once
//每條記錄的索引
let index = 0;
//循環(huán)加載數(shù)據(jù)
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每頁(yè)多少條
let pageCount = Math.min(curTotal , once);
window.requestAnimationFrame(function(){
let fragment = document.createDocumentFragment();
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
fragment.appendChild(li)
}
ul.appendChild(fragment)
loop(curTotal - pageCount,curIndex + pageCount)
})
}
loop(total,index);
復(fù)制代碼
最后
本文更多的是提供一個(gè)思路,通過(guò)時(shí)間分片的方式來(lái)同時(shí)加載大量簡(jiǎn)單DOM。對(duì)于復(fù)雜DOM的情況,一般會(huì)用到虛擬列表的方式來(lái)實(shí)現(xiàn),關(guān)于這一問(wèn)題,會(huì)持續(xù)整理,敬請(qǐng)期待。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

文章名稱:「前端進(jìn)階」高性能渲染十萬(wàn)條數(shù)據(jù)(時(shí)間分片)-創(chuàng)新互聯(lián)
本文來(lái)源:http://www.rwnh.cn/article2/gdhoc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、Google、網(wǎng)站排名、網(wǎng)站維護(hù)軟件開(kāi)發(fā)、面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
曲周县| 和田县| 卢龙县| 隆回县| 合作市| 南平市| 竹山县| 嘉黎县| 日照市| 镇雄县| 梧州市| 璧山县| 楚雄市| 乡城县| 武隆县| 麟游县| 河南省| 正定县| 卓尼县| 大同县| 东平县| 河西区| 谷城县| 广丰县| 新疆| 赣榆县| 大田县| 佛坪县| 德令哈市| 称多县| 青浦区| 莱芜市| 大埔县| 铅山县| 焦作市| 庐江县| 颍上县| 文水县| 星子县| 治县。| 黑河市|