用Chrome開(kāi)發(fā)者工具做JavaScript性能分析

英文原文:Zack Grossbart,編譯:伯樂(lè)在線——王筱
你的網(wǎng)站正常運(yùn)轉(zhuǎn)」現(xiàn)在我們來(lái)讓它運(yùn)轉(zhuǎn)的更快差导。網(wǎng)站的性能由頁(yè)面載入速度和代碼執(zhí)行效率決定。一些服務(wù)可以讓你的網(wǎng)站載入更快蒸矛,比如壓縮JS和CDN,但是讓代碼執(zhí)行的更快你要做的事情。
代碼中很小的改動(dòng)都可能對(duì)性能造成巨大的影響雏掠。快速靈活的網(wǎng)站和可怕的“無(wú)響應(yīng)腳本”對(duì)話框可能只有幾行代碼的差別劣像。這篇文章告訴你如何通過(guò)用Chrome開(kāi)發(fā)者工具(Chrome Developer Tools)找到這幾行關(guān)鍵的代碼乡话。
設(shè)置一個(gè)基線
我們來(lái)看一個(gè)簡(jiǎn)單的“顏色排序器”應(yīng)用,這個(gè)應(yīng)用展示了一個(gè)由各種顏色構(gòu)成的網(wǎng)格耳奕,你可以拖拽這些顏色進(jìn)行混合绑青。每一個(gè)點(diǎn)都是一個(gè)div標(biāo)簽加上一些讓它看起來(lái)是圓的的CSS。


生成這些顏色是需要技巧的屋群,所以我借助了”Making Annoying Rainbows in Javascript”闸婴。
頁(yè)面載入的很快,但還是花費(fèi)了一些時(shí)間芍躏,在渲染之前還閃了一下邪乍。是時(shí)候?qū)@個(gè)頁(yè)面進(jìn)行性能分析讓它更快了。
在開(kāi)始做性能優(yōu)化的時(shí)候要設(shè)置一個(gè)基線对竣,來(lái)明確這個(gè)頁(yè)面的速度到底怎樣庇楞。這個(gè)基線可以讓你知道自己是否做了優(yōu)化并幫助你權(quán)衡利弊。在這片文章里我們要使用chrome開(kāi)發(fā)者工具否纬。
性能分析器(profiler)是chrome開(kāi)發(fā)者工具的一部分吕晌,點(diǎn)擊小扳手下面的工具菜單就可以打開(kāi)它。Firebug也有一些性能評(píng)測(cè)工具临燃,但是webkit內(nèi)核的瀏覽器(chrome和safari)在對(duì)代碼進(jìn)行性能分析和展示時(shí)間線方面是最棒的睛驳。Chrome還提供一種很棒的事件跟蹤工具膜廊,叫做 speed tracer
在時(shí)間線(timeline)標(biāo)簽下開(kāi)始記錄溃论,載入頁(yè)面然后停止記錄,這樣就設(shè)置了一個(gè)基線钥勋。(打開(kāi)chrome開(kāi)發(fā)者工具,點(diǎn)擊“時(shí)間線”標(biāo)簽算灸,然后點(diǎn)擊窗口底部圓形的黑色“記錄”圖標(biāo)開(kāi)始記錄)。chrome是很智能的菲驴,只有頁(yè)面開(kāi)始載入的時(shí)候才會(huì)開(kāi)始記錄。我記錄了三次然后取了平均值,以防我的電腦在第一次測(cè)試的時(shí)候運(yùn)行的很慢先煎。
用chrome開(kāi)發(fā)者工具進(jìn)行JS性能分析

我的平均基線,也就是從第一個(gè)請(qǐng)求到頁(yè)面全部渲染結(jié)束所花費(fèi)的時(shí)間是1.25秒遥倦。這個(gè)時(shí)間不是太長(zhǎng),但是對(duì)于這樣一個(gè)小的頁(yè)面來(lái)說(shuō)也不算好占锯。
我想讓代碼執(zhí)行的更快袒哥,但是我并不知道是什么讓它慢下來(lái)的。性能分析器(profiler)幫助我找到原因消略。

創(chuàng)建一個(gè)Profile
時(shí)間線(timeline)告訴我們代碼運(yùn)行花費(fèi)的時(shí)間堡称,但是并沒(méi)有幫助我們知道代碼運(yùn)行的時(shí)候發(fā)生了什么。我們可以做一些改動(dòng)然后不斷的測(cè)每次代碼運(yùn)行的時(shí)間艺演,但這是盲目的却紧。profiles給我們提供了更好的方法。profiler告訴我們哪些函數(shù)的執(zhí)行占用了大部分時(shí)間钞艇。讓我們切換到chrome開(kāi)發(fā)者工具的“Profiles”標(biāo)簽頁(yè)開(kāi)始性能測(cè)試啄寡,這里一共提供了三種類型的性能測(cè)試。

  1. javascript cpu 性能測(cè)試
    顯示javascript占用了多少CPU
  2. css選擇器性能測(cè)試
    顯示處理CSS選擇器占用的CPU
  3. 堆椓ㄕ眨快照
    顯示javascript對(duì)象的內(nèi)存占用情況
    我們想要javascript代碼執(zhí)行的更快挺物,所以我們進(jìn)行CPU性能測(cè)試。我們開(kāi)始性能測(cè)試飘弧,刷新頁(yè)面然后停止识藤。
    用chrome開(kāi)發(fā)者工具進(jìn)行JS性能分析

    通過(guò)性能分析首先知道很多函數(shù)在執(zhí)行〈瘟妫“顏色排序器”使用了jQuery和jQuery UI,來(lái)處理些管理插件和解析表達(dá)式之類的事情痴昧。我發(fā)現(xiàn)列表最頂端的是decimalToHex和makeColorSorter兩個(gè)函數(shù)。這兩個(gè)函數(shù)占用了CPU13.2%的時(shí)間冠王,這是做優(yōu)化的好地方赶撰。
    我們可以點(diǎn)擊函數(shù)調(diào)用旁邊的“下一個(gè)”箭頭來(lái)查看完整的函數(shù)調(diào)用堆棧。展開(kāi)后柱彻,可以看到decimalToHex是被makeColorSorter調(diào)用的豪娜,makeColorSorter是通過(guò)$(document).ready調(diào)用的。
    代碼如下
$(document).ready( function() {
    makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121);
    makeSortable();
});

弄清楚這兩個(gè)函數(shù)是哪里調(diào)用的哟楷,也就弄清楚了讓顏色可以排序并不是最大的性能問(wèn)題瘤载。通常情況下性能問(wèn)題都是由多余的排序操作造成的,但是在我的代碼中相比與排序增加DOM元素花費(fèi)了更多時(shí)間卖擅。
我想要讓這些函數(shù)執(zhí)行的更快鸣奔,但是首先我想要將我的改動(dòng)區(qū)隔開(kāi)墨技。在頁(yè)面載入過(guò)程中會(huì)發(fā)生很多事情,我不想要這些影響到我的性能分析扣汪。

區(qū)隔問(wèn)題
我做了第二個(gè)版本私痹,這個(gè)版本中“顏色排序器”在我點(diǎn)擊按鈕之后才載入统刮,而不是在document ready的時(shí)候載入侥蒙。這就把文檔載入的過(guò)程分離出去鞭衩,讓我可以只對(duì)顏色分類進(jìn)行性能測(cè)試娃善。調(diào)完性能之后我可以立刻改回去聚磺。
讓我們調(diào)用新的函數(shù)testColorSorter并把它綁定到一個(gè)可點(diǎn)擊的按鈕上。

function testColorSorter() {
    makeColorSorter(.05, .05, .05, 0, 2, 4, 128, 127, 121);
    makeSortable();
}
<button id="clickMe" onclick="testColorSorter();">Click me</button>

在我們進(jìn)行性能分析之前改變應(yīng)用可能導(dǎo)致意外的結(jié)果蜒蕾。這個(gè)改動(dòng)看起來(lái)很安全咪啡,但是我還是要重新運(yùn)行性能檢測(cè)器來(lái)看看我是不是無(wú)意中改變了什么撤摸。我會(huì)開(kāi)始一次新的性能分析褒纲,點(diǎn)擊應(yīng)用中的按鈕然后停止外厂。


我首先注意到decimalToHex函數(shù)的載入只占用了4.23%的時(shí)間汁蝶。這是代碼執(zhí)行花費(fèi)時(shí)間最多的地方论悴。我們創(chuàng)建一個(gè)新的基線來(lái)看看這個(gè)方案對(duì)代碼有多大的優(yōu)化膀估。
用chrome開(kāi)發(fā)者工具進(jìn)行JS性能分析

有些事件在我點(diǎn)擊按鈕之前有觸發(fā)了察纯,但是我只關(guān)注從我點(diǎn)擊鼠標(biāo)到瀏覽器渲染“顏色排序器”花費(fèi)的時(shí)間针肥。鼠標(biāo)在390毫秒時(shí)點(diǎn)擊慰枕,渲染事件在726毫秒處被觸發(fā)。726減去390得到我的基線336毫秒博肋。和第一個(gè)基線一樣我重復(fù)了3次來(lái)取平均值蜂厅。
這時(shí),我知道如何獲得并且得到了代碼確切的運(yùn)行時(shí)間礁遵,我們已經(jīng)準(zhǔn)備好開(kāi)始解決問(wèn)題了佣耐。

讓代碼更高效
性能分析器只告訴我們哪個(gè)函數(shù)造成的問(wèn)題兼砖,所以我們要查看下函數(shù)的源碼來(lái)了解函數(shù)做了些什么既棺。

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;
}

“顏色排序器”中的每一個(gè)顏色點(diǎn)都有一個(gè)16進(jìn)制的色彩值丸冕,例如#86F01B和#2345FE.這些值表示一種顏色中紅,綠眼姐,藍(lán)三原色各自的數(shù)值。例如的背景色是#2456FE,代表紅色的值是36罢杉,綠色的值是86贡歧,藍(lán)色的是254,每一個(gè)數(shù)值必須是0到255之間的律想。
decimalToHex函數(shù)把這用RGB值表示的顏色轉(zhuǎn)化為頁(yè)面中我們使用的16進(jìn)制顏色蜘欲。這個(gè)函數(shù)十分的簡(jiǎn)單晌柬,但是我還是留下了一個(gè)可以去掉的調(diào)試代碼console.log在那里年碘。
decimalToHex 函數(shù)還在數(shù)字之前加上了補(bǔ)位屿衅。這是很重要的一點(diǎn)莹弊,因?yàn)橛行?0進(jìn)制數(shù)字對(duì)應(yīng)的是1個(gè)16進(jìn)制數(shù)字忍弛。比如十進(jìn)制中的10對(duì)應(yīng)著16進(jìn)制中的C,但是在CSS中需要一個(gè)兩位數(shù)蔗彤。為了讓這個(gè)進(jìn)制換算更快速,我們讓這段代碼不是那么泛化然遏。我知道每個(gè)需要補(bǔ)位的數(shù)字長(zhǎng)度都為1待侵,所以我們可以這樣重寫(xiě)這個(gè)函數(shù)姨裸。

function decimalToHex(d) {
    var hex = Number(d).toString(16);
    return hex.length === 1 ? '0' + hex : hex; 
}

第三個(gè)版本的“顏色排序器”只有在需要補(bǔ)位的時(shí)候才改變字符串,并且不用調(diào)用substr函數(shù)中狂。有了這個(gè)新函數(shù)胃榕,運(yùn)行時(shí)間是137毫秒。再次對(duì)代碼進(jìn)行性能測(cè)試苦掘,可以發(fā)現(xiàn)decimalToHex函數(shù)只占用了總時(shí)間的%0.04,到了列表的下部鹤啡。


我們還可以發(fā)現(xiàn)占用CPU最多的函數(shù)是 jQuery的e.extend.merge递瑰。我不知道這個(gè)函數(shù)的作用抖部,因?yàn)榇a是壓縮過(guò)的慎颗。我可以使用開(kāi)發(fā)版本的jQuery言询,但是我發(fā)現(xiàn)這個(gè)函數(shù)是被makeColorSorter調(diào)用的。所以下一步我們先讓這個(gè)函數(shù)執(zhí)行的更快夫啊。

減小改動(dòng)
“顏色排序器”中的多彩顏色是用過(guò)正弦曲線生成的涮母。在光譜中設(shè)置一個(gè)中心點(diǎn)叛本,然后以一定的偏移來(lái)創(chuàng)建這個(gè)曲線彤钟。這就把顏色變成了一個(gè)“彩虹模型”逸雹。我們還可以通過(guò)改變紅綠藍(lán)三原色的使用頻率來(lái)改變顏色云挟。

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函數(shù)。這些調(diào)用非常的糟糕休蟹,因?yàn)槊看螆?zhí)行都會(huì)調(diào)用decimalToHex函數(shù),這意味著decimalToHex函數(shù)會(huì)被多調(diào)用2倍的次數(shù)绑榴。這個(gè)函數(shù)大幅度的改變了DOM結(jié)構(gòu)翔怎。每次循環(huán)赤套,都向id為colors的div中添加一個(gè)新的div珊膜。這就讓我懷疑這就是e.extend.mergefunction做的事情。用性能分析器做一個(gè)小實(shí)驗(yàn)就可以搞清楚。
我想要一次把所有的div添加進(jìn)去堪遂,而不是在每個(gè)循環(huán)中添加一個(gè)新的div萌庆。創(chuàng)建一個(gè)變量來(lái)存儲(chǔ)數(shù)據(jù)践险,然后在最后一次性添加進(jìn)去。

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);
}

這個(gè)小改動(dòng)意味著DOM只在添加所有div的時(shí)候做一次改變彭则。用時(shí)間線進(jìn)行測(cè)試俯抖,我們發(fā)現(xiàn)從點(diǎn)擊到渲染花費(fèi)了31毫秒芬萍。這個(gè)dom變動(dòng),使得第四個(gè)版本的運(yùn)行時(shí)間降低了86%北戏。我可以再次打開(kāi)性能分析器(profiler)漫蛔,發(fā)現(xiàn)e.extend.merge函數(shù)占用了很少的時(shí)間惩猫,在列表中已經(jīng)看不到它了。
我們還可以完全移除decimalToHex函數(shù)讓代碼更快一點(diǎn)拌阴。因?yàn)镃SS支持RGB顏色奶镶,所以我們不需要把他們轉(zhuǎn)換到16進(jìn)制〕д颍現(xiàn)在我們可以這樣寫(xiě)makeColorSorter函數(shù)。

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);
}

第五個(gè)版本的執(zhí)行只用了26毫秒而且代碼行數(shù)從28行減少到18行酌媒。
在你的應(yīng)用中進(jìn)行Javascript性能分析
實(shí)際工作中的應(yīng)用要比“顏色排序器”復(fù)雜的多秒咨,但是做性能分析要遵循同樣的基本原則

  1. 設(shè)置一個(gè)基線掌挚,這樣你就知道你是從何處開(kāi)始的。
  2. 把問(wèn)題從應(yīng)用的其他代碼隔離出來(lái)陡厘。
  3. 在一個(gè)可控的環(huán)境下進(jìn)行優(yōu)化糙置,頻繁的使用時(shí)間線(timelines)和性能分析器(profiles)

還有一些性能優(yōu)化的準(zhǔn)則

  1. 從最慢的部分開(kāi)始是目,這樣在時(shí)間優(yōu)化上可以得到最大的提升。
  2. 控制環(huán)境网持。如果你換了電腦或者做了任何大的改動(dòng)功舀,都要設(shè)置新的基線。
  3. 多次分析以防你電腦的異常導(dǎo)致得到不正確的結(jié)果列敲。

每個(gè)人都想要他的網(wǎng)站更快帖汞,你必須開(kāi)發(fā)新的功能翩蘸,但是新的功能通常會(huì)讓網(wǎng)站更慢。所以花費(fèi)時(shí)間來(lái)做性能優(yōu)化是有價(jià)值的扶踊。
性能分析和優(yōu)化使得最終版顏色分類器的執(zhí)行時(shí)間減少了92%郎任。你的網(wǎng)站可以變快多少舶治?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末霉猛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铸磅,老刑警劉巖阅仔,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件八酒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)画饥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)抖甘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)葫慎,“玉大人偷办,你說(shuō)我怎么就攤上這事”冢” “怎么了逐工?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)棕硫。 經(jīng)常有香客問(wèn)我袒啼,道長(zhǎng)蚓再,這世上最難降的妖魔是什么摘仅? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮六荒,結(jié)果婚禮上掏击,老公的妹妹穿的比我還像新娘砚亭。我一直安慰自己,他們只是感情好添祸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布膝捞。 她就那樣靜靜地躺著蔬咬,像睡著了一般沐寺。 火紅的嫁衣襯著肌膚如雪混坞。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,096評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音厨诸,去河邊找鬼。 笑死绘趋,一個(gè)胖子當(dāng)著我的面吹牛颗管,可吹牛的內(nèi)容都是我干的垦江。 我是一名探鬼主播比吭,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了慷彤?” 一聲冷哼從身側(cè)響起底哗,我...
    開(kāi)封第一講書(shū)人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涕癣,沒(méi)想到半個(gè)月后坠韩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體只搁,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氢惋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年焰望,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了熊赖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陷猫,死狀恐怖秫舌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绣檬,我是刑警寧澤足陨,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站娇未,受9級(jí)特大地震影響墨缘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜零抬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一镊讼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧平夜,春花似錦、人聲如沸玩裙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枉圃。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旭等,已是汗流浹背搔耕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工鲸睛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拳亿。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓鹅经,卻偏偏與公主長(zhǎng)得像瞬雹,于是被迫代替她去往敵國(guó)和親涌哲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阀圾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容