你的網站正常運轉。現在我們來讓它運轉的更快。網站的效能由頁面載入速度和代碼執行效率決定。一些服務可以讓你的網站載入更快,比如壓縮和CDN,但是讓代碼執行的更快你要做的事情。
代碼中很小的改動都可能對效能造成巨大的影響。快速靈活的網站和可怕的“無響應指令碼”對話方塊可能只有幾行代碼的差別。這篇文章告訴你如何通過用Chrome開發人員工具(Chrome Developer Tools)找到這幾行關鍵的代碼。
設定一個基準
我們來看一個簡單的“顏色排序器”應用,這個應用展示了一個由各種顏色構成的網格,你可以拖拽這些顏色進行混合。每一個點都是一個div標籤加上一些讓它看起來是圓的的CSS。
產生這些顏色是需要技巧的,所以我藉助了”Making Annoying Rainbows in Javascript”。
頁面載入的很快,但還是花費了一些時間,在渲染之前還閃了一下。是時候對這個頁面進行效能分析讓它更快了。
在開始做效能最佳化的時候要設定一個基準,來明確這個頁面的速度到底怎樣。這個基準可以讓你知道自己是否做了最佳化並協助你權衡利弊。在這片文章裡我們要使用chrome開發人員工具。
效能分析器(profiler)是chrome開發人員工具的一部分,點擊小扳手下面的工具菜單就可以開啟它。Firebug也有一些效能評測工具, 但是webkit核心的瀏覽器(chrome和safari)在對代碼進行效能分析和展示時間軸方面是最棒的。Chrome還提供一種很棒的事件跟蹤工 具,叫做speed tracer。
在時間軸(timeline)標籤下開始記錄,載入頁面然後停止記錄,這樣就設定了一個基準。(開啟chrome開發人員工具,點擊“時間軸”標籤, 然後點擊視窗底部圓形的黑色“記錄”表徵圖開始記錄)。chrome是很智能的,只有頁面開始載入的時候才會開始記錄。我記錄了三次然後取了平均值,以防我 的電腦在第一次測試的時候啟動並執行很慢。
我的平均基準,也就是從第一個請求到頁面全部渲染結束所花費的時間是1.25秒。這個時間不是太長,但是對於這樣一個小的頁面來說也不算好。
我想讓代碼執行的更快,但是我並不知道是什麼讓它慢下來的。效能分析器(profiler)協助我找到原因。
建立一個Profile
時間軸(timeline)告訴我們代碼運行花費的時間,但是並沒有協助我們知道代碼啟動並執行時候發生了什麼。我們可以做一些改動然後不斷的測每次代 碼啟動並執行時間,但這是盲目的。profiles給我們提供了更好的方法。profiler告訴我們哪些函數的執行佔用了大部分時間。讓我們切換到 chrome開發人員工具的“Profiles”標籤頁開始效能測試,這裡一共提供了三種類型的效能測試。
1、 javascript cpu 效能測試
顯示javascript佔用了多少CPU
2、 css選取器效能測試
顯示處理CSS選取器佔用的CPU
3、 堆棧快照
顯示javascript對象的記憶體佔用情況
我們想要javascript代碼執行的更快,所以我們進行CPU效能測試。我們開始效能測試,重新整理頁面然後停止。
通過效能分析首Crowdsourced Security Testing道很多函數在執行。“顏色排序器”使用了jQuery和jQuery UI,來處理些管理外掛程式和解析運算式之類的事情。我發現列表最頂端的是decimalToHex和makeColorSorter兩個函數。這兩個函數占 用了CPU13.2%的時間,這是做最佳化的好地方。
我們可以點擊函數調用旁邊的“下一個”箭頭來查看完整的函數呼叫堆疊。展開後,可以看到decimalToHex是被makeColorSorter調用的,makeColorSorter是通過$(document).ready調用的。
代碼如下
$(document).ready(function() {
makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127,121);
makeSortable();
});
弄清楚這兩個函數是哪裡調用的,也就弄清楚了讓顏色可以排序並不是最大的效能問題。通常情況下效能問題都是由多餘的排序操作造成的,但是在My Code中相比與排序增加DOM元素花費了更多時間。
我想要讓這些函數執行的更快,但是首先我想要將我的改動區隔開。在頁面載入過程中會發生很多事情,我不想要這些影響到我的效能分析。
區隔問題
我做了第二個版本,這個版本中“顏色排序器”在我點擊按鈕之後才載入,而不是在document ready的時候載入。這就把文檔載入的過程分離出去,讓我可以只對顏色分類進行效能測試。調完效能之後我可以立刻改回去。
讓我們調用新的函數testColorSorter並把它綁定到一個可點擊的按鈕上。
function testColorSorter() {
makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121);
makeSortable(); }
<button id=“clickMe” onclick=“testColorSorter();”>Click me</button>
在我們進行效能分析之前改變應用可能導致意外的結果。這個改動看起來很安全,但是我還是要重新運行效能檢測器來看看我是不是無意中改變了什麼。我會開始一次新的效能分析,點擊應用中的按鈕然後停止。
我首先注意到decimalToHex函數的載入只佔用了4.23%的時間。這是代碼執行花費時間最多的地方。我們建立一個新的基準來看看這個方案對代碼有多大的最佳化。
有些事件在我點擊按鈕之前有觸發了,但是我只關注從我點擊滑鼠到瀏覽器渲染“顏色排序器”花費的時間。滑鼠在390毫秒時點擊,渲染事件在726毫秒處被觸發。726減去390得到我的基準336毫秒。和第一個基準一樣我重複了3次來取平均值。
這時,我知道如何獲得並且得到了代碼確切的已耗用時間,我們已經準備好開始解決問題了。
讓代碼更高效
效能分析器只告訴我們哪個函數造成的問題,所以我們要查看下函數的源碼來瞭解函數做了些什麼。
function decimalToHex(d) {
var hex = Number(d).toString(16);
hex = “00”.substr(0, 2 - hex.length) + hex;
console.log(‘converting ’ + d + ‘ to ’ + hex);
return hex;
}
“顏色排序器”中的每一個顏色點都有一個16進位的色彩值,例如#86F01B和#2345FE.這些值表示一種顏色中紅,綠,藍三原色各自的數值。例如的背景色是#2456FE,代表紅色的值是36,綠色的值是86,藍色的是254,每一個數值必須是0到255之間的。
decimalToHex函數把這用RGB值表示的顏色轉化為頁面中我們使用的16進位顏色。這個函數十分的簡單,但是我還是留下了一個可以去掉的調試代碼console.log在那裡。
decimalToHex 函數還在數字之前加上了補位。這是很重要的一點,因為有些10進位數字對應的是1個16進位數字。比如十進位中的10對應著16進位中的C,但是在CSS 中需要一個兩位元。為了讓這個進位換算更快速,我們讓這段代碼不是那麼泛化。我知道每個需要補位的數字長度都為1,所以我們可以這樣重寫這個函數。
function decimalToHex(d) {
var hex = Number(d).toString(16);
return hex.length === 1 ? ‘0’ + hex : hex;
}
第三個版本的“顏色排序器”只有在需要補位的時候才改變字串,並且不用調用substr函數。有了這個新函數,已耗用時間是137毫秒。再次對代碼進行效能測試,可以發現decimalToHex函數只佔用了總時間的%0.04,到了列表的下部。
我們還可以發現佔用CPU最多的函數是 jQuery的e.extend.merge。我不知道這個函數的作用,因為代碼是壓縮過的。我可以使用開發版本的jQuery,但是我發現這個函數是被 makeColorSorter調用的。所以下一步我們先讓這個函數執行的更快。
減小改動
“顏色排序器”中的多彩顏色是用過正弦曲線產生的。在光譜中設定一個中心點,然後以一定的位移來建立這個曲線。這就把顏色變成了一個“彩虹模型”。我們還可以通過改變紅綠藍三原色的使用頻率來改變顏色。
function makeColorSorter(frequency1, frequency2, frequency3, phase1, phase2, phase3, center, width, len) {
for (var i = 0; i < len; ++i) {
var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center);
var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center);
var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center);
console.log(‘red: ’ + decimalToHex(red));
console.log(‘green: ’ + decimalToHex(green));
console.log(‘blue: ’ + decimalToHex(blue));
var div = $(‘<div class=“colorBlock”></div>’); div.css(‘background-color’, ‘#’ +
decimalToHex(red) + decimalToHex(green) + decimalToHex(blue));
$(‘#colors’).append(div);
}
}
我們要去掉console.log函數。這些調用非常的糟糕,因為每次執行都會調用decimalToHex函數,這意味著 decimalToHex函數會被多調用2倍的次數。這個函數大幅度的改變了DOM結構。每次迴圈,都向id為colors的div中添加一個新的 div。這就讓我懷疑這就是e.extend.mergefunction做的事情。用效能分析器做一個小實驗就可以搞清楚。
我想要一次把所有的div添加進去,而不是在每個迴圈中添加一個新的div。建立一個變數來儲存資料,然後在最後一次性添加進去。
function makeColorSorter(frequency1, frequency2, frequency3, phase1, phase2, phase3, center, width, len) {
var colors = “”;
for (var i = 0; i < len; ++i) {
var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center);
var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center);
var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center);
colors += ‘<div class=“colorBlock” style=“background-color: #’ +
decimalToHex(red) + decimalToHex(green) + decimalToHex(blue) + ‘”>
</div>’;
}
$(‘#colors’).append(colors);
}
這個小改動意味著DOM只在添加所有div的時候做一次改變。用時間軸進行測試,我們發現從點擊到渲染花費了31毫秒。這個dom變動,使得第四個 版本的已耗用時間降低了86%。我可以再次開啟效能分析器(profiler),發現e.extend.merge函數佔用了很少的時間,在列表中已經看不 到它了。
我們還可以完全移除decimalToHex函數讓代碼更快一點。因為CSS支援RGB顏色,所以我們不需要把他們轉換到16進位。現在我們可以這樣寫makeColorSorter函數。
function makeColorSorter(frequency1, frequency2, frequency3, phase1, phase2, phase3, center, width, len) {
var colors = “”;
for (var i = 0; i < len; ++i) {
var red = Math.floor(Math.sin(frequency1 * i + phase1) * width + center);
var green = Math.floor(Math.sin(frequency2 * i + phase2) * width + center);
var blue = Math.floor(Math.sin(frequency3 * i + phase3) * width + center);
colors += ‘<div class=“colorBlock” style=“background-color: rgb(’ + red + ‘,’
+ green + ‘,’ + blue + ‘)“></div>’;
}
$(‘#colors’).append(colors);
}
第五個版本的執行只用了26毫秒而且程式碼數從28行減少到18行。
在你的應用中進行Javascript效能分析
實際工作中的應用要比“顏色排序器”複雜的多,但是做效能分析要遵循同樣的基本原則
1、 設定一個基準,這樣你就知道你是從何處開始的。
2、 把問題從應用的其他代碼隔離出來。
3、 在一個可控的環境下進行最佳化,頻繁的使用時間線(timelines)和效能分析器(profiles)
還有一些效能最佳化的準則
1、 從最慢的部分開始,這樣在時間最佳化上可以得到最大的提升。
2、 控制環境。如果你換了電腦或者做了任何大的改動,都要設定新的基準。
3、 多次分析以防你電腦的異常導致得到不正確的結果。
每個人都想要他的網站更快,你必須開發新的功能,但是新的功能通常會讓網站更慢。所以花費時間來做效能最佳化是有價值的。
效能分析和最佳化使得最終版顏色分類器的執行時間減少了92%。你的網站可以變快多少?
英文原文:Zack Grossbart,編譯:伯樂線上——王筱
文章來源: 伯樂線上
註:相關網站建設技巧閱讀請移步到建站教程頻道。