2021-07-18【性能優(yōu)化相關(guān)】內(nèi)存泄露導(dǎo)致的瀏覽器崩潰

最近給客戶部署的一個項目瞎嬉,客戶反饋說持續(xù)運行一段時間后瀏覽器會崩潰兜蠕。
收到反饋后扰肌,我們使用自己的設(shè)備進(jìn)行測試,持續(xù)運行了48小時熊杨,頁面并沒有崩潰曙旭。后來找到幾臺老舊機型來測試,運行幾小時后確實出現(xiàn)了崩潰的現(xiàn)象晶府。排查原因應(yīng)該是代碼運行中桂躏,在某些低端設(shè)備上內(nèi)存釋放不及時,長時間運行后內(nèi)存積累川陆,導(dǎo)致頁面崩潰剂习。

在不能強制客戶升級硬件設(shè)備的條件下,只能通過優(yōu)化代碼,排查可能存在內(nèi)存泄漏地方鳞绕。

1失仁、頁面中有很多通過svg和Lottie實現(xiàn)的動畫,并通過v-show來控制不同動畫的顯示和隱藏们何。通過調(diào)試發(fā)現(xiàn)萄焦,在v-show值為false,即動畫display:none的情況下冤竹,動畫依然在占用內(nèi)存拂封,所以在優(yōu)化時將v-show改為了v-if。

2鹦蠕、頁面中的動畫多處使用了setInterval定時器冒签,通過封裝公共方法,使用requestAnimationFrame和setTimeout代替setInterval钟病。

3萧恕、對于一些簡單功能,如顯示當(dāng)前時間档悠,去掉插件廊鸥,通過原生js實現(xiàn)望浩。同時對于頁面中外部依賴的處理辖所、第三方插件的按需引入。

因為Network面板記錄了與服務(wù)器交互的具體細(xì)節(jié)磨德,所以可以通過Network面板來查詢當(dāng)前頁面的資源請求缘回。
在這里我們可以看到發(fā)起的請求數(shù)量,傳輸體積以及解壓縮后的體積典挑,同時還可以知道哪些資源是命中了強緩存酥宴,哪些資源命中的協(xié)商緩存。

拓展

-關(guān)于Lottie動畫

Lottie 是 Airbnb 開源的一套跨平臺的完整的動畫效果解決方案您觉,設(shè)計師可以使用 Adobe After Effects 設(shè)計出漂亮的動畫之后拙寡,使用 Lottic 提供的 Bodymovin 插件將設(shè)計好的動畫導(dǎo)出成 JSON 格式,就可以直接運用在 iOS琳水、Android肆糕、Web 和 React Native之上,無需其他額外操作在孝。

關(guān)于Lottie動畫 https://juejin.cn/post/6844903661760413704

-下面解釋一下使用requestAnimationFrame 的原理

  • 何為requestAnimationFrame
    window.requestAnimationFrame() 告訴瀏覽器——你希望執(zhí)行一個動畫诚啃,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動畫。該方法需要傳入一個回調(diào)函數(shù)作為參數(shù)私沮,該回調(diào)函數(shù)會在瀏覽器下一次重繪之前執(zhí)行始赎。

注意:若你想在瀏覽器下次重繪之前繼續(xù)更新下一幀動畫,那么回調(diào)函數(shù)自身必須再次調(diào)用window.requestAnimationFrame()。

  • requestAnimationFrame的優(yōu)勢
    requestAnimationFrame 比起 setTimeout造垛、setInterval的優(yōu)勢主要有兩點:
    1魔招、requestAnimationFrame 會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成五辽,并且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率仆百,一般來說,這個頻率為每秒60幀奔脐。
    2俄周、在隱藏或不可見的元素中,requestAnimationFrame將不會進(jìn)行重繪或回流髓迎,這當(dāng)然就意味著更少的的cpu峦朗,gpu和內(nèi)存使用量。

  • 關(guān)于requestAnimationFrame的使用 - 用js實現(xiàn)一個無限循環(huán)的動畫排龄。

//大家首先想到的肯定是定時器吧~
<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>
    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
//es6中字符串拼接用${變量名}的方式引用變量
//ES6中``內(nèi)的所有東西都被解析為字符串波势,相對于ES5的字符串拼接來說更為方便

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`;
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }
    setInterval(function(){
         render()
    },1000/60)

</script>
</body>
</html>
效果圖.gif

那我們使用requestAnimationFrame函數(shù) 試試

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>
    var e = document.getElementById("e");
    var flag = true;
    var left = 0;

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }
    //requestAnimationFrame效果
    (function animloop() {
        render();
        window.requestAnimationFrame(animloop);
    })();
</script>
</body>
</html>

隨之而來的,有個問題:效果是實現(xiàn)了但是怎么停止requestAnimationFrame函數(shù)橄维?是否有類似clearInterval這樣的類似方法尺铣?
答案是確定的 必須有:cancelAnimationFrame()接收一個參數(shù) requestAnimationFrame默認(rèn)返回一個id,cancelAnimationFrame只需要傳入這個id就可以停止了争舞。

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>
    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
    var rafId = null
    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }
    //requestAnimationFrame效果
    (function animloop(time) {
        console.log(time,Date.now())
        render();
        rafId = requestAnimationFrame(animloop);
        //如果left等于50 停止動畫
        if(left == 50){
            cancelAnimationFrame(rafId); //停止動畫
        }
    })();

    //setInterval效果
    // setInterval(function(){
    //     render()
    // },1000/60)
</script>
</body>
</html>

2凛忿、如果我想動畫頻率降低怎么做,默認(rèn)情況下竞川,requestAnimationFrame執(zhí)行頻率是1000/60,大概是16ms多執(zhí)一次店溢。
如果我們想每50ms執(zhí)行一次怎么辦呢?

<!doctype html>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        #e{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
            zoom: 1;
        }
    </style>
</head>
<body>
<div id="e"></div>
<script>


    var e = document.getElementById("e");
    var flag = true;
    var left = 0;
    //當(dāng)前執(zhí)行時間
    var nowTime = 0;
    //記錄每次動畫執(zhí)行結(jié)束的時間
    var lastTime = Date.now();
    //我們自己定義的動畫時間差值
    var diffTime = 40;

    function render() {
        if(flag == true){
            if(left>=100){
                flag = false
            }
            e.style.left = ` ${left++}px`
        }else{
            if(left<=0){
                flag = true
            }
            e.style.left = ` ${left--}px`
        }
    }

    //requestAnimationFrame效果
    (function animloop() {
        //記錄當(dāng)前時間
        nowTime = Date.now()
        // 當(dāng)前時間-上次執(zhí)行時間如果大于diffTime委乌,那么執(zhí)行動畫床牧,并更新上次執(zhí)行時間
        if(nowTime-lastTime > diffTime){
            lastTime = nowTime
            render();
        }
        requestAnimationFrame(animloop);

    })()
</script>
</body>
</html>
//@我是一個前端
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市遭贸,隨后出現(xiàn)的幾起案子戈咳,更是在濱河造成了極大的恐慌,老刑警劉巖壕吹,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件著蛙,死亡現(xiàn)場離奇詭異,居然都是意外死亡算利,警方通過查閱死者的電腦和手機册踩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來效拭,“玉大人暂吉,你說我怎么就攤上這事胖秒。” “怎么了慕的?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵阎肝,是天一觀的道長。 經(jīng)常有香客問我肮街,道長风题,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任嫉父,我火速辦了婚禮沛硅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绕辖。我一直安慰自己摇肌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布仪际。 她就那樣靜靜地躺著围小,像睡著了一般。 火紅的嫁衣襯著肌膚如雪树碱。 梳的紋絲不亂的頭發(fā)上肯适,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音成榜,去河邊找鬼框舔。 笑死,一個胖子當(dāng)著我的面吹牛伦连,可吹牛的內(nèi)容都是我干的雨饺。 我是一名探鬼主播钳垮,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惑淳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饺窿?” 一聲冷哼從身側(cè)響起歧焦,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肚医,沒想到半個月后绢馍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡肠套,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年舰涌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片你稚。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓷耙,死狀恐怖朱躺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搁痛,我是刑警寧澤长搀,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站鸡典,受9級特大地震影響源请,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彻况,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一谁尸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纽甘,春花似錦症汹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泽裳,卻和暖如春瞒斩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涮总。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工胸囱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瀑梗。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓烹笔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抛丽。 傳聞我的和親對象是個殘疾皇子谤职,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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

  • 線程與進(jìn)程 進(jìn)程和線程的概念可以這樣理解: 進(jìn)程是一個工廠,工廠有它的獨立資源--工廠之間相互獨立--線程是工廠中...
    Odeng閱讀 847評論 0 1
  • 在瀏覽器渲染過程與性能優(yōu)化一文中(建議先去看一下這篇文章再來閱讀本文)亿鲜,我們了解與認(rèn)識了瀏覽器的關(guān)鍵渲染路徑以及如...
    SylvanasSun閱讀 4,664評論 1 5
  • 參考鏈接 由于網(wǎng)上的關(guān)于瀏覽器進(jìn)程和JS進(jìn)程允蜈、JS線程和事件循環(huán)之間的關(guān)系模糊不清,這里主要是查閱資料進(jìn)行詳細(xì)匯總...
    johe_jianshu閱讀 1,000評論 0 2
  • 1. 瀏覽器渲染機制 瀏覽器采用流式布局模型(Flow Based Layout) 瀏覽器會把HTML解析成DOM...
    高磊_IT閱讀 743評論 0 3
  • 作者: fridayhttp://forsomething.cn/ 阿里云針對新客戶的活動正在進(jìn)行中蒿柳,感興趣的可以...
    FFriday閱讀 10,749評論 1 7