首页
/
每日頭條
/
科技
/
進階前端的最佳方法
進階前端的最佳方法
更新时间:2024-05-08 01:32:28

前言

在實際工作中,我們很少會遇到一次性需要向頁面中插入大量數據的情況,但是為了豐富我們的知識體系,我們有必要了解并清楚當遇到大量數據時,如何才能在不卡主頁面的情況下渲染數據,以及其中背後的原理。

對于一次性插入大量數據的情況,一般有兩種做法:

  1. 時間分片
  2. 虛拟列表

最粗暴的做法(一次性渲染)

我們先來看看最粗暴的做法,一次性将大量數據插入到頁面中:

我們對十萬條記錄進行循環操作,JS的運行時間為187ms,還是蠻快的,但是最終渲染完成後的總時間确是2844ms。

簡單說明一下,為何兩次console.log的結果時間差異巨大,并且是如何簡單來統計JS運行時間和總渲染時間:

  • 在 JS 的Event Loop中,當JS引擎所管理的執行棧中的事件以及所有微任務事件全部執行完後,才會觸發渲染線程對頁面進行渲染
  • 第一個console.log的觸發時間是在頁面進行渲染之前,此時得到的間隔時間為JS運行所需要的時間
  • 第二個console.log是放到 setTimeout 中的,它的觸發時間是在渲染完成,在下一次Event Loop中執行的

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

對于大量數據渲染的時候,JS運算并不是性能的瓶頸,性能的瓶頸主要在于渲染階段

使用定時器

從上面的例子,我們已經知道,頁面的卡頓是由于同時渲染大量DOM所引起的,所以我們考慮将渲染過程分批進行

我們可以看到,頁面加載的時間已經非常快了,每次刷新時可以很快的看到第一屏的所有數據,但是當我們快速滾動頁面的時候,會發現頁面出現閃屏或白屏的現象

為什麼會出現閃屏現象呢

首先,理清一些概念。FPS表示的是每秒鐘畫面更新次數。我們平時所看到的連續畫面都是由一幅幅靜止畫面組成的,每幅畫面稱為一幀,FPS是描述幀變化速度的物理量。

大多數電腦顯示器的刷新頻率是60Hz,大概相當于每秒鐘重繪60次,FPS為60frame/s,為這個值的設定受屏幕分辨率、屏幕尺寸和顯卡的影響。

因此,當你對着電腦屏幕什麼也不做的情況下,大多顯示器也會以每秒60次的頻率正在不斷的更新屏幕上的圖像。

為什麼你感覺不到這個變化?

那是因為人的眼睛有視覺停留效應,即前一副畫面留在大腦的印象還沒消失,緊接着後一副畫面就跟上來了, 這中間隻間隔了16.7ms(1000/60≈16.7),所以會讓你誤以為屏幕上的圖像是靜止不動的。

而屏幕給你的這種感覺是對的,試想一下,如果刷新頻率變成1次/秒,屏幕上的圖像就會出現嚴重的閃爍, 這樣就很容易引起眼睛疲勞、酸痛和頭暈目眩等症狀。

大多數浏覽器都會對重繪操作加以限制,不超過顯示器的重繪頻率,因為即使超過那個頻率用戶體驗也不會有提升。 因此,最平滑動畫的最佳循環間隔是1000ms/60,約等于16.6ms。

直觀感受,不同幀率的體驗:

  • 幀率能夠達到 50 ~ 60 FPS 的動畫将會相當流暢,讓人倍感舒适;
  • 幀率在 30 ~ 50 FPS 之間的動畫,因各人敏感程度不同,舒适度因人而異;
  • 幀率在 30 FPS 以下的動畫,讓人感覺到明顯的卡頓和不适感;
  • 幀率波動很大的動畫,亦會使人感覺到卡頓。

簡單聊一下 setTimeout 和閃屏現象

  • setTimeout的執行時間并不是确定的。在JS中,setTimeout任務被放進事件隊列中,隻有主線程執行完才會去檢查事件隊列中的任務是否需要執行,因此setTimeout的實際執行時間可能會比其設定的時間晚一些。
  • 刷新頻率受屏幕分辨率和屏幕尺寸的影響,因此不同設備的刷新頻率可能會不同,而setTimeout隻能設置一個固定時間間隔,這個時間不一定和屏幕的刷新時間相同。

以上兩種情況都會導緻setTimeout的執行步調和屏幕的刷新步調不一緻。

在setTimeout中對dom進行操作,必須要等到屏幕下次繪制時才能更新到屏幕上,如果兩者步調不一緻,就可能導緻中間某一幀的操作被跨越過去,而直接更新下一幀的元素,從而導緻丢幀現象。

使用 requestAnimationFrame

與setTimeout相比,requestAnimationFrame最大的優勢是由系統來決定回調函數的執行時機。

如果屏幕刷新率是60Hz,那麼回調函數就每16.7ms被執行一次,如果刷新率是75Hz,那麼這個時間間隔就變成了1000/75=13.3ms,換句話說就是,requestAnimationFrame的步伐跟着系統的刷新步伐走。它能保證回調函數在屏幕每一次的刷新間隔中隻被執行一次,這樣就不會引起丢幀現象。

我們使用requestAnimationFrame來進行分批渲染:

看下效果

進階前端的最佳方法(高性能渲染十萬條數據)1

我們可以看到,頁面加載的速度很快,并且滾動的時候,也很流暢沒有出現閃爍丢幀的現象。

這就結束了麼,還可以再優化麼?

當然~~

使用 documentFragment

先解釋一下什麼是 DocumentFragment ,文獻引用自MDN

DocumentFragment,文檔片段接口,表示一個沒有父級文件的最小文檔對象。它被作為一個輕量版的Document使用,用于存儲已排好版的或尚未打理好格式的XML片段。最大的區别是因為DocumentFragment不是真實DOM樹的一部分,它的變化不會觸發DOM樹的(重新渲染) ,且不會導緻性能等問題。可以使用document.createDocumentFragment方法或者構造函數來創建一個空的DocumentFragment

從MDN的說明中,我們得知DocumentFragments是DOM節點,但并不是DOM樹的一部分,可以認為是存在内存中的,所以将子元素插入到文檔片段時不會引起頁面回流。

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

最後修改代碼如下:

作者:雲中橋鍊接:https://juejin.im/post/5d76f469f265da039a28aff7來源:掘金著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

,
Comments
Welcome to tft每日頭條 comments! Please keep conversations courteous and on-topic. To fosterproductive and respectful conversations, you may see comments from our Community Managers.
Sign up to post
Sort by
Show More Comments
推荐阅读
蜀山戰紀獲得新武器
蜀山戰紀獲得新武器
近來,越來越多的優秀影視作品被改編成手遊,其種類繁雜,五花八門,改編手遊的質量也是良莠不齊,部分改編的遊戲不僅畫面糟糕,而且劇情乏善可陳,遊戲方式也一成不變,讓不少原著的粉絲們大失所望。但是在這之中也不乏做工精美,遊戲方式别具一格的的用心之...
2024-05-08
環衛工人拾金不昧萬元财物歸原
環衛工人拾金不昧萬元财物歸原
12月23日,城關區環衛局的兩位環衛工用自己的實際行動展現了環衛人拾金不昧的精神品質。12月23日早上8時30分,城關區環衛局保潔一公司保潔員錢金運在省政府保潔時撿到一個皮包,包内裝有兩條煙。她詢問過往路人,但沒有找到失主,隻好将失物送到站...
2024-05-08
保隆科技上海松江工廠
保隆科技上海松江工廠
保隆科技上海松江工廠?中證網訊(王珞)保隆科技日前發布“123中期戰略”,即在公司成立30周年之時,實現營收目标100億元、淨利潤目标10億元;在智能底盤、智能駕駛、汽車傳感器、輕量化汽車結構件等領域持續投入,緻力于成為“智能化與輕量化汽車...
2024-05-08
蘋果13和蘋果13pro max續航測試
蘋果13和蘋果13pro max續航測試
3月8日,小米集團副總裁、紅米品牌經理盧偉冰,在預熱紅米K50系列新機的時候提出了一個問題:現在大家公認的續航表現最好的手機是哪款?盧偉冰之所以提出這個問題,是為了抛磚引玉,借此來宣傳紅米K50系列強大的續航能力,但讓他沒想到的是,絕大多數...
2024-05-08
液壓泵的工作原理示意圖
液壓泵的工作原理示意圖
液壓泵是為液壓傳動提供加壓液體的一種液壓元件,是泵的一種。雖然不同類型的液壓泵的結構大不相同,但是在安裝、使用維護方面存在許多共同點,如果不規範操作的話,可能會導緻故障的發生。液壓泵的功能是把動力機(如電動機和内燃機等)的機械能轉換成液體的...
2024-05-08
Copyright 2023-2024 - www.tftnews.com All Rights Reserved