原文出處: 賣燒烤夫斯基
滷煮在前面已經向大家介紹了Chrome開發者工具的一些功能面板,其中包括Elements、Network、Resources基礎功能部分和Sources進階功能部分,對於一般的網站項目來說,其實就是需要這幾個面板功能就可以了(再加上console面板這個萬精油)。它們的作用大多數情況下是幫助你進行功能開發的。然而在你開發應用級別的網站項目的時候,隨着代碼的增加,功能的增加,性能會逐漸成爲你需要關注的部分。那麼網站的性能問題具體是指什麼呢?在滷煮看來,一個網站的性能主要關乎兩項,一是加載性能、二是執行性能。第一項可以利用Network來分析,我以後會再次寫一篇關於它的文章分享滷煮的提高加載速度的經驗,不過在此之前,我強烈推薦你去閱讀《web高性能開發指南》這本書中的十四條黃金建議,這是我閱讀過的最精華的書籍之一,雖然只有短短的一百多頁,但對你的幫助確實無法估量的。而第二項性能問題就體現在內存泄露上,這也是我們這篇文章探討的問題——通過Timeline來分析你的網站內存泄露。
雖然瀏覽器日新月異,每一次網站版本的更新就意味着JavaScript、css的速度更加快速,然而作爲一名前端人員,是很有必要去發現項目中的性能的雞肋的。在衆多性能優化中,內存泄露相比於其他性能缺陷(網絡加載)不容易發現和解決,因爲內存泄露設計到瀏覽器處理內存的一些機制並且同時涉及到到你的編寫的代碼質量。在一些小的項目中,當內存泄露還不足以讓你重視,但隨着項目複雜度的增加,內存問題就會暴露出來。首先內存佔有過多導致你的網站響應速度(非ajax)變得慢,就感覺自己的網頁卡死了一樣;然後你會看到任務管理器的內存佔用率飆升;到最後電腦感覺死了機一樣。這種情況在小內存的設備上情況會更加嚴重。所以,找到內存泄露並且解決它是處理這類問題的關鍵。
在本文中,滷煮會通過個人和官方的例子,幫助諸位理解Timeline的使用方法和分析數據的方法。首先我們依然爲該面板區分爲四個區域,然後對它們裏面的各個功能進行逐一介紹:
雖然Timeline在執行它的任務時會顯得花花綠綠讓人眼花繚亂,不過不用擔心,滷煮用一句話概括它的功能就是:描述你的網站在某些時候做的事情和呈現出的狀態。我們看下區域1中的功能先:
在區域1主題是一個從左到右的時間軸,在運行時它裏面會呈現出各種顏色塊(下文中會介紹)。頂部有一條工具欄,從左到右,一次表示:
1、開始運行Timeline檢測網頁。點亮圓點,Timline開始監聽工作,在此熄滅圓點,Timeline展示出監聽階段網站的執行狀態。
2、清除所有的監聽信息。將Timeline復原。
3、查找和過濾監控信息。點擊會彈出一個小框框,裏面可以搜索或者顯示隱藏你要找的信息。
4、手動回收你網站內內存垃圾。
5、View:監控信息的展示方式,目前有兩種,柱狀圖和條狀圖,在展示的事例中,滷煮默認選擇條狀圖。
6、在偵聽過程中希望抓取的信息,js堆棧、內存、繪圖等。。。。
區域2是區域1的完全版,雖然他們都是展示的信息視圖,在在區域2種,圖示會變得更加詳細,更加精準。一般我們查看監控視圖都在區域2種進行。
區域3是展示的是一些內存信息,總共會有四條曲線的變化。它們對應表示如下圖所示:
區域4中展示的是在區域2種某種行爲的詳細信息和圖表信息。
在對功能做了簡單的介紹之後我們用一個測試用例來了解一下Timeline的具體用法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <!DOCTYPE html> <html> <head> <title></title> <style type="text/css"> div{ height: 20px; widows: 20px; font-size: 26px; font-weight: bold; } </style> </head> <body> <div id="div1"> HELLO WORLD0 </div> <div id="div2"> HELLO WORLD2 </div> <div id="div3"> HELLO WORLD3 </div> <div id="div4"> HELLO WORLD4 </div> <div id="div5"> HELLO WORLD5 </div> <div id="div6"> HELLO WORLD6 </div> <div id="div7"> HELLO WORLD7 </div> <button id="btn">click me</button> <script type="text/javascript"> var k = 0; function x() { if(k >= 7) return; document.getElementById('div'+(++k)).innerHTML = 'hello world' } document.getElementById('btn').addEventListener('click', x); </script> </body> </html> |
新建一個html項目,然後再Chrome中打開它,接着按F12切換到開發者模式,選擇Timeline面板,點亮區域1左上角的那個小圓圈,你可以看到它變成了紅色,然後開始操作界面。連續按下button執行我們的js程序,等待所有div的內容都變成hello world的時候再次點擊小圓圈,熄滅它,這時候你就可以看到Timeline中的圖表信息了,如下圖所示:
在區域1中,左下角有一組數字2.0MB-2.1MB,它的意思是在你剛剛操作界面這段時間內,內存增長了0.1MB。底部那塊淺藍色的區域是內存變化的示意圖。從左到右,我們可以看到剛剛瀏覽器監聽了4000ms左右的行爲動作,從0~4000ms內區域1中列出了所有的狀態。接下來我們來仔細分析一下這些狀態的具體信息。在區域2種,滾動鼠標的滾輪,你會看到時間軸會放大縮小,現在我們隨着滾輪不斷縮小時間軸的範圍,我們可以看到一些各個顏色的橫條:
在操作界面時,我們點擊了一次button,它耗費了大約1ms的時間完成了從響應事件到重繪節目的一些列動作,上圖就是在789.6ms-790.6ms中完成的這次click事件所發生的瀏覽器行爲,其他的事件行爲你同樣可以通過滑動滑輪縮小區域來觀察他們的情況。在區域2種,每一種顏色的橫條其實都代表了它自己的獨特的意義:
每次點擊都回到了上面的圖一樣執行若干事件,所以我們操作界面時發生的事情可以做一個大致的瞭解,我們滑動滾輪把時間軸恢復到原始尺寸做個總體分析:
可以看到,每一次點擊事件都伴隨着一些列的變化:html的重新渲染,界面重新佈局,視圖重繪。很多情況下,每個事件的發生都會引起一系列的變化。在區域2種,我們可以通過點擊某一個橫條,然後在區域4種更加詳細地觀察它的具體信息。我們以執行函數x爲例觀察它的執行期的狀態。
隨着在事件發生的,除了dom的渲染和繪製等事件的發生之外,相應地內存也會發生變化,而這種變化我們可以從區域3種看到:
在上文中已經向大家做過區域3的介紹,我們可以看到js堆在視圖中不斷地再增長,這時因爲由事件導致的界面繪製和dom重新渲染會導致內存的增加,所以每一次點擊,導致了內存相應地增長。同樣的,如果區域3種其他曲線的變化會引起藍色線條的變化,這是因爲其他(綠色代表的dom節點數、黃色代表的事件數)也會佔有內存。因此,你可以通過藍色曲線的變化形勢來確定其他個數的變化,當然最直觀的方式就是觀察括號中的數字變化。js內存的變化曲線是比較複雜的,裏面參雜了很多因素。我們所列出來的例子實際上是很簡單的。目前相信你對Timeline的使用有了一定的認識,下面我們通過一些Google瀏覽器官方的實例來更好的瞭解它的作用(因爲觀看示例都必須FQ,所以滷煮把js代碼copy出來,至於簡單的html代碼你可以自己寫。如果可以FQ的同學就無所謂了!)
(官方測試用例一) 查看內存增長,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
varx=[];
functioncreateSomeNodes(){
vardiv,
i=100,
frag=document.createDocumentFragment();
for(;i>0;i--){
div=document.createElement("div");
div.appendChild(document.createTextNode(i+"
- "+newDate().toTimeString()));
frag.appendChild(div);
}
document.getElementById("nodes").appendChild(frag);
}
functiongrow(){
x.push(newArray(1000000).join('x'));
createSomeNodes();//不停地在界面創建div元素
setTimeout(grow,1000);
}
|
通過多次執行grow函數,我們在Timeline中看到了一張內存變化的圖:
通過上圖可以看出js堆隨着dom節點增加而增長,通過點擊區域1中頂部的垃圾箱,可以手動回收一些內存。正常的內存分析圖示鋸齒形狀(高低起伏,最終迴歸於初始階段的水平位置)而不是像上圖那樣階梯式增長,如果你看到藍色線條沒有回落的情況,並且DOM節點數沒有返回到開始時的數目,你就可以懷疑有內存泄露了。
下面是一個用異常手段展示的正常例子,說明了內存被創建了又如何被回收。你可以看到曲線是鋸齒型的上下起伏狀態,在最後js內存回到了初始的狀態。(官方示例二) js代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
varintervalId=null,params;
functioncreateChunks(){
vardiv,foo,i,str;
for(i=0;i<20;i++){
div=document.createElement("div");
str=newArray(1000000).join('x');
foo={
str:str,
div:div
};
div.foo=foo;
}
}
functionstart(){
if(intervalId){
return;
}
intervalId=setInterval(createChunks,1000);
}
functionstop(){
if(intervalId){
clearInterval(intervalId);
}
intervalId=null;
}
|
執行start函數若干次,然後執行stop函數,可以生成一張內存劇烈變化的圖:
還有很多官方實例,你可以通過它們來觀察各種情況下內存的變化曲線,在這裏我們不一一列出。在這裏滷煮選擇試圖的形式是條狀圖,你可以在區域1中選擇其他的顯示方式,這個全靠個人的愛好了。總而言之,Timeline可以幫助我們分析內存變化狀態(Timeline直譯就是時間軸的意思吧),通過對它的觀察來確定我的項目是否存在着內存泄露以及是什麼地方引起的泄露。圖表在展示上雖然很直觀但是缺少數字的精確,通過示圖曲線的變化我們可以瞭解瀏覽器上發生的事件,最主要的是瞭解內存變化的趨勢。而如果你希望進一步分析這些內存狀態,那麼接下來你就可以打開Profiles來幹活了。這將是我們這個系列的下一篇文章要介紹的。