記一次頁面卡頓排查

記一次頁面卡頓排查

前述

前段時間上線的一個移動端的項目,因爲開發時間倉促,一直被用戶投訴頁面卡頓。如今終於有時間來好好排查一下,看究竟是什麼緣由。業務代碼都不是本身寫的,這是頗爲頭疼的問題。到了本身手上也只能努力的填坑了,伐開心。css

chrome Timeline分析

首先固然是祭出開發神器--chrome,來看看頁面的fps和js執行時間都是什麼樣子的。
本文不是介紹Timeline的知識,請還不瞭解的同窗自行學習。傳送門:https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/timeline-toolhtml

圖片描述

果真fps是鋸齒狀的,頂上伴隨着紅條(可能存在性能問題的地方)。從圖中能夠發現,出現fps較低的地方,大都伴隨着過多的script執行耗時(黃色部分)。接着咱們選取一段fps較低的時間段,來看下具體有哪些event。前端

圖片描述

從圖中能夠看出,這個函數執行了118ms(固然頁面卡頓還有別的地方引發,我就不一一描述出來了),而要確保頁面不卡頓的時間是16.7ms。這顯然要致使卡頓。這個函數內發生了不少事件。我發現了一個很糟糕的事,強制reflow,這但是前端性能的大忌了。而這個迴流佔用了大部分的函數執行時間。這個reflow是發生在「renderCommlist」函數內的,而後我點進這個函數看作了些什麼操做。代碼以下:node

function renderCommlist(data, $dom) {
    var prex = getMaidianPre();
    totalCount = data.cnt - 0;
    if (totalCount != 0) {
        $("#palmrobtimes").show();
        indexComm = fillCommListData(data, prex, indexComm);
        var render = template.compile(document.getElementById("tmpl_pro_item").innerHTML);
        var html = render(data);
        renderCommlistAsyc(html, $dom);
        $("#toTop").show()
    } else {
        commListEmpty($dom);
        $("#toTop").hide()
    }
    dataLoading = false
}

根據執行的順序我能夠判定這個reflow發生對應的是「 $("#toTop").show()」這句。這就讓我詫異了,一個zepto的show()方法居然會致使這麼嚴重的後果。我是長姿式了。而「#toTop」對應的DOM是這樣的:web

圖片描述

「toTop」是被一個fixed的標籤包裹起來的。根據個人所學一個脫離文檔流的dom不該該能形成這麼嚴重的reflow啊。因此咱們要來zepto的show到底作了一些什麼事情。chrome

接着咱們來看Call Tree。看看show裏面調用了哪些函數。app

圖片描述

我發現,show裏面調用了n,t.fn.animate,t.fn.anim等函數。主要發時間都消耗在了t.fn.anim上了。從函數名上看,這應該是動畫相關的函數。我只是想要個顯示元素,居然調用了動畫函數,不知道爲何。從「Layout」後面的連接點進去能夠定位到觸發「Layout」的,代碼以下:框架

// trigger page reflow so new elements can animate
this.size() && this.get(0).clientLeft

這樣我就明白了。就是這一句致使強制reflow。而我是要顯示個元素,不要動畫,這顯然是不必的。我翻看了下源代碼,這裏居然還有註釋。「爲了新的元素可以執行動畫,觸發頁面迴流」。原來做者是故意的,不過顯然低估了reflow的威力。其實也不是全部的場景會形成這麼嚴重的迴流耗時,只是個人場景比較「幸運」,在調用的這個函數的同時,程序往頁面裏append了DOM,放大了這個reflow。dom

對zepto的show函數的分析

至於show函數是怎麼調用到animate的我仍是比較好奇。在源碼裏查看了下。在zepto的核心模塊「zepto.js」裏其實show是這樣的:前端性能

show: function(){
  return this.each(function(){
    this.style.display == "none" && (this.style.display = '')
    if (getComputedStyle(this, '').getPropertyValue("display") == "none")
      this.style.display = defaultDisplay(this.nodeName)
  })
},

並無去調用anim的。因此我就全局搜索了下「$.fn.show」發現這個函數是在「fx_methods.js」模塊裏的。

$.fn.show = function(speed, callback) {
    origShow.call(this)
    if (speed === undefined) speed = 0
    else this.css('opacity', 0)
    return anim(this, speed, 1, '1,1', callback)
}

這樣就明白了,這個函數把上面的show給覆蓋掉了,添加了動畫。而anim又調用了「fx.js」裏的「$.fn.animate」,這樣就看到了上面的執行效果。不夠我仍是以爲動畫不必。其實「fx.js」和「fx_methods.js「,實際上是能夠不用打包到zepto裏的,zepto的默認模塊裏也沒這兩個。

總結

這只是頁面卡頓的一個點,固然還有不少,咱們的頁面卡頓就是由這樣一個一個的點形成的。因此本身之後平常多多注意頁面的性能。多用chrome dev來分析頁面存在的性能問題。而後不要迷信開源框架,也是有缺陷的。

相關文章
相關標籤/搜索