自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Chrome Timeline來優(yōu)化頁面性能

開發(fā) 開發(fā)工具
有時候,我們就是會不由自主地寫出一些低效的代碼,嚴(yán)重影響頁面運(yùn)行的效率?;蛘呶覀兘邮值捻椖恐?,前人寫出來的代碼千奇百怪,比如為了一個 Canvas 特效需要同時繪制 600 個三角形,又比如 Coding.net 的任務(wù)中心需要同時 watch 上萬個變量的變化等等。那么,如果我們遇到了一個比較低效的頁面,應(yīng)該如何去優(yōu)化它呢?

有時候,我們就是會不由自主地寫出一些低效的代碼,嚴(yán)重影響頁面運(yùn)行的效率?;蛘呶覀兘邮值捻椖恐校叭藢懗鰜淼拇a千奇百怪,比如為了一個 Canvas 特效需要同時繪制 600 個三角形,又比如 Coding.net 的任務(wù)中心需要同時 watch 上萬個變量的變化等等。那么,如果我們遇到了一個比較低效的頁面,應(yīng)該如何去優(yōu)化它呢?

優(yōu)化前的準(zhǔn)備:知己知彼

在一切開始之前,我們先打開 F12 面板,熟悉一下我們接下來要用到的工具:Timeline:

 

嗯沒錯就是它。下面逐一介紹一下吧。區(qū)域 1 是一個縮略圖,可以看到除了時間軸以外被上下分成了四塊,分別代表 FPS、CPU 時間、網(wǎng)絡(luò)通信時間、堆棧占用;這個縮略圖可以橫向縮放,白色區(qū)域是下面可以看到的時間段(灰色當(dāng)然是不可見的啦)。區(qū)域 2 可以看一些交互事件,例如你滾動了一下頁面,那么這里會出現(xiàn)一個 scroll 的線段,線段覆蓋的范圍就是滾動經(jīng)過的時間。區(qū)域 3 則是具體的事件列表了。

一開始沒有記錄的時候,所有的區(qū)域都是空的。開始統(tǒng)計和結(jié)束統(tǒng)計都很簡單,左上角那坨黑色的圓圈就是。它右邊那個長得像“禁止通行”的按鈕是用來清除現(xiàn)有記錄的。當(dāng)有數(shù)據(jù)的時候,我們把鼠標(biāo)滾輪向上滾,可以看到區(qū)域被放大了:

 

短短的時間里,瀏覽器做了這么多事情。對于一般的屏幕,原則上來說一秒要往屏幕上繪制 60 幀,所以理論上講我們一幀內(nèi)的計算時間不能超過 16 毫秒,然而瀏覽器除了執(zhí)行我們的代碼以外,還要干點(diǎn)別的(例如計算 CSS,播放音頻……),所以其實我們能用的只有 10~12 毫秒左右。

差不多熟悉操作了,那么就來一下實戰(zhàn)吧!假如有一天,你接手了這樣一段代碼:

  1. <!-- 一段小動畫:點(diǎn)擊按鈕之后會有一個爆炸的粒子效果 --> 
  2. <!DOCTYPE html> 
  3. <html> 
  4. <head> 
  5.     <meta charset="utf-8"
  6.     <title>Test</title> 
  7.     <style> 
  8.         .main { 
  9.             position: relative
  10.             width: 500px; 
  11.             height: 500px; 
  12.             background: #000; 
  13.             overflow: hidden; 
  14.         } 
  15.         .circle { 
  16.             position: absolute
  17.             border-radius: 50%; 
  18.             border: 1px solid #FFF; 
  19.             width: 8px; 
  20.             height: 8px; 
  21.         } 
  22.     </style> 
  23. </head> 
  24. <body> 
  25.     <div class="main"></div> 
  26.     <hr> 
  27.     <button onclick="showAnimation()">點(diǎn)我</button> 
  28.     <script src="jquery.min.js"></script> 
  29.     <script src="animation.js"></script> 
  30. </body> 
  31. </html> 
  1. // animation.js  
  2.   
  3. // 粒子總數(shù)  
  4. var COUNT = 500;  
  5. // 重力  
  6. var G = -0.1;  
  7. // 摩擦力  
  8. var F = -0.04;  
  9.   
  10. function init() {  
  11.     for (var i = 0; i < COUNT; i++) {  
  12.         var d = Math.random() * 2 * Math.PI;  
  13.         var v = Math.random() * 5;  
  14.         var circle = $('<div id="circle-' + i + '" class="circle" data-x="250" data-y="250" data-d="' + d + '" data-v="' + v + '"></div>');  
  15.         circle.appendTo($('.main'));  
  16.     }  
  17. }  
  18.   
  19. function updateCircle() {  
  20.     for (var i = 0; i < COUNT; i++) {  
  21.         var x = parseFloat($('#circle-' + i).attr('data-x'));  
  22.         var y = parseFloat($('#circle-' + i).attr('data-y'));  
  23.         var d = parseFloat($('#circle-' + i).attr('data-d'));  
  24.         var v = parseFloat($('#circle-' + i).attr('data-v'));  
  25.         var vx = v * Math.cos(d);  
  26.         var vy = v * Math.sin(d);  
  27.         if (Math.abs(vx) < 1e-9) vx = 0;  
  28.         // 速度分量改變  
  29.         vx += F * Math.cos(d);  
  30.         vy += F * Math.sin(d) + G;  
  31.         // 計算新速度  
  32.         v = Math.sqrt(vx * vx + vy * vy);  
  33.         if (vy > 0) d = Math.acos(vx / v);  
  34.         else d = -Math.acos(vx / v);  
  35.         // 位移分量改變  
  36.         x += vx;  
  37.         y += vy;  
  38.         $('#circle-' + i).attr('data-x', x);  
  39.         $('#circle-' + i).attr('data-y', y);  
  40.         $('#circle-' + i).attr('data-d', d);  
  41.         $('#circle-' + i).attr('data-v', v);  
  42.         $('#circle-' + i).css({'top': 400 - y, 'left': x});  
  43.     }  
  44. }  
  45.   
  46. var interval = null;  
  47.   
  48. function showAnimation() {  
  49.     if (interval) clearInterval(interval);  
  50.     $('.main').html('');  
  51.     init();  
  52.     interval = setInterval(updateCircle, 1000 / 60);  
  53. }  

效果如下(右上角的 FPS 計數(shù)器是 Chrome 調(diào)試工具自帶的):

 

只有 10 FPS……10 FPS……坑爹呢這是!

 

好吧,打開 Timeline,按下記錄按鈕,點(diǎn)一下頁面中的“點(diǎn)我”,稍微過一會兒停止記錄,就會得到一些數(shù)據(jù)。放大一些,對 jQuery 比較熟悉的同學(xué)可以看出來,這些大部分是 jQuery 的函數(shù)。我們點(diǎn)一下那個 updateCircle 的區(qū)塊,然后看下面:

 

這里告訴我們,這個函數(shù)運(yùn)行了多久、函數(shù)代碼在哪兒。我們點(diǎn)一下那個鏈接,于是就跳到了 Source 頁:

 

是不是很震撼,之前這個頁面只是用來 Debug 的,沒想到現(xiàn)在居然帶了精確到行的運(yùn)行時間統(tǒng)計。當(dāng)然,這個時間是當(dāng)前這一行在“剛才我們點(diǎn)擊的區(qū)塊對應(yīng)的執(zhí)行時間段”中運(yùn)行的時間。所以我們就拿最慢的幾句話來下手吧!

優(yōu)化一:減少 DOM 操作

看到這幾行代碼,***反應(yīng)是:mdzz。本來 DOM 操作就慢,還要在字符串和 float 之間轉(zhuǎn)來轉(zhuǎn)去。果斷改掉!于是用一個單獨(dú)的數(shù)組來存 x、y、d、v 這些屬性。

  1. var objects = []; 
  2. // 在 init 函數(shù)中 
  3. objects.push({ 
  4.     x: 250, 
  5.     y: 250, 
  6.     d: d, 
  7.     v: v 
  8. }); 
  9. // 在 updateCircle 函數(shù)中 
  10. var x = objects[i].x; 
  11. var y = objects[i].y; 
  12. var d = objects[i].d; 
  13. var v = objects[i].v; 
  14. // …. 
  15. objects[i].x = x; 
  16. objects[i].y = y; 
  17. objects[i].d = d; 
  18. objects[i].v = v; 

 

效果顯著!我們再來看一下精確到行的數(shù)據(jù):

 

優(yōu)化二:減少不必要的運(yùn)算

所以最耗時的那句話已經(jīng)變成了計算 vx 和 vy,畢竟三角函數(shù)算法比較復(fù)雜嘛,可以理解。至于后面的三角函數(shù)為什么那么快,我猜可能是 Chrome 的 V8 引擎將其緩存了(這句話不保證正確性)。然而不知道大家有沒有發(fā)現(xiàn),其實計算 d 完全沒必要!我們只需要存 vx 和 vy 即可,不需要存 v 和 d!

  1. // init 
  2. var vx = v * Math.cos(d); 
  3. var vy = v * Math.sin(d); 
  4. objects.push({ 
  5.     x: 250, 
  6.     y: 250, 
  7.     vx: vx, 
  8.     vy: vy 
  9. }); 
  10. // updateCircle 
  11. var vx = objects[i].vx; 
  12. var vy = objects[i].vy; 
  13. // 計算新速度 
  14. var v = Math.sqrt(vx * vx + vy * vy); 
  15. if (Math.abs(vx) < 1e-9) vx = 0; 
  16. // 速度分量改變 
  17. vx += F * vx / v; 
  18. vy += F * vy / v + G; 
  19. // …. 
  20. objects[i].vx = vx; 
  21. objects[i].vy = vy; 

 

只有加減乘除和開平方運(yùn)算,每次比原來的時間又少了兩毫秒。從流暢的角度來說其實已經(jīng)可以滿幀運(yùn)行了,然而為什么我還是覺得偶爾會有點(diǎn)卡呢?

優(yōu)化三:替換 setInterval

既然偶爾會掉幀,那么就看看是怎么掉的唄~原則上來說,在每一次瀏覽器進(jìn)行繪制之前,Timeline 里面應(yīng)該有一個叫 Paint 的事件,就像這樣:

 

看到這些綠色的東西了沒?就是它們!看上面的時間軸,雖然代碼中 setInterval 的長度是 1000/16 毫秒,但是其實根本不能保證!所以我們需要使用 requestAnimationFrame 來代替它。這是瀏覽器自帶的專門為動畫服務(wù)的函數(shù),瀏覽器會自動優(yōu)化這個函數(shù)的調(diào)用時機(jī)。并且如果頁面被隱藏,瀏覽器還會自動暫停調(diào)用,有效地減少了 CPU 的開銷。

  1. // 在 updateCircle ***加一句 
  2. requestAnimationFrame(updateCircle); 
  3. // 去掉全部跟 setInterval 有關(guān)的句子,把 showAnimation ***一句直接改成這個 
  4. updateCircle(); 

 

我們至少可以保證,我們每算一次,屏幕上就會顯示一次,因此不會掉幀(前提是每計算一次的時間小于 12ms)。但是雖然計算時間少了,瀏覽器重計算樣式、繪制圖像的時間可是一點(diǎn)都沒變。能不能再做優(yōu)化呢?

優(yōu)化四:使用硬件加速、避免反復(fù)查找元素

如果我們用 transform 來代替 left 和 top 來對元素進(jìn)行定位,那么瀏覽器會為這個元素單***立一個合成層,專門使用 GPU 進(jìn)行渲染,這樣可以把重計算的代價降到***。有興趣的同學(xué)可以研究一下“CSS 硬件加速”的機(jī)制。同時,我們可以緩存一下 jQuery 的元素(或者 DOM 元素),這樣不用每次都重新查找,也能稍微提高一點(diǎn)效率。如果把元素緩存在 objects 數(shù)組中,那么連 id 都不用寫了!

  1. // init 
  2. var circle = $('<div class="circle"></div>'); 
  3. objects.push({ 
  4.     x: 250, 
  5.     y: 250, 
  6.     vx: vx, 
  7.     vy: vy, 
  8.     // 其實可以只存 DOM,不存 jQuery 對象 
  9.     circle: circle[0] 
  10. }); 
  11. // updateCircle 里面 for 循環(huán)的***一句話替換掉 
  12. objects[i].circle.style.transform = 'translate(' + x + 'px, ' + (400 - y) + 'px)' 

 

看起來是不是很爽了?

其實,優(yōu)化是無止境的,例如我在 init 函數(shù)中完全可以不用 jQuery,改用 createDocumentFragment 來拼接元素,這樣初始化的時間就可以急劇縮短;調(diào)換 updateCircle 中的幾個語句的順序,在 V8 引擎下效率可能會有一定的提升;甚至還可以結(jié)合 Profile 面板來分析內(nèi)存占用,查看瀏覽器繪圖的細(xì)節(jié)……然而個人感覺并用不到這么極限的優(yōu)化。對于一個項目來說,如果單純?yōu)榱藘?yōu)化而寫一些奇怪的代碼,是很不合算的。

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2011-05-11 17:26:17

Minify

2021-05-11 10:03:06

性能優(yōu)化工具Performance

2009-09-08 09:45:23

App Engine性

2017-05-10 14:47:37

Headless Ch頁面 Docker

2024-02-02 15:21:08

工具頁面性能

2019-03-14 15:38:19

ReactJavascript前端

2017-01-19 19:07:28

iOS進(jìn)階性能優(yōu)化

2020-12-21 08:32:07

內(nèi)存性能優(yōu)化

2021-05-13 09:43:03

Flutter研發(fā)模式

2010-08-18 09:26:56

DB2性能調(diào)優(yōu)

2022-04-27 10:53:34

web優(yōu)化性能

2017-04-25 16:20:10

頁面優(yōu)化滾動優(yōu)化

2011-08-24 17:23:10

2017-11-27 14:58:01

MySQL高并發(fā)優(yōu)化性能調(diào)優(yōu)

2017-12-14 14:32:30

.Net內(nèi)存代碼

2023-12-18 09:08:40

IstioSidecar代理服務(wù)

2017-01-19 15:27:24

Android性能優(yōu)化Lint

2022-06-06 22:36:55

渲染性能CSS

2013-07-10 10:24:10

2019-03-04 10:45:57

Linux Cockp系統(tǒng)性能命令
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號