国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

記錄一次利用Timeline Performance工具進行 React性能優化的真實案例

jsyzchen / 3482人閱讀

摘要:出現紅幀表示頁面已經超負荷,會出現卡頓,響應緩慢等現象。因此當滑動周日歷時已經不會有紅幀發生了。我的目的是每一次遞歸會調用一次與但是這樣寫只會在遞歸結束時調用一次因此修改如下這樣優化之后,發現內存占用下降一些,但是紅幀仍然存在。

性能優化可以說是衡量一個前端程序員react使用水平的重要標準。

在學習react之初的時候,由于對react不夠了解,寫的項目雖然功能都實現了,但是性能優化方面的考慮卻做得很少,因此回過頭來發現自己以前寫的react代碼確實有點糟糕。

為了提高自己的react水平,閑暇之余就把以前的老項目拿出來分析優化,看看都有哪些問題。這里就以我以前做過的一個《投資日歷》為例做一次優化記錄。

項目線上地址:https://www.itiger.com/activi...

優化工具timeline/performance基礎使用教程:
https://developers.google.com...

chrome在版本57還是58的時候,將Timeline更名為performance

該項目主要的難點與性能瓶頸在于日歷的左右滑動與切換。由于需求定制程度非常高,沒有合適的第三方日歷插件,所以就自己實現了一個。支持周日歷與月日歷的切換,支持左右滑動切換日期。

滑動效果僅支持移動端

問題出現在公司一款老的android測試機,發現動畫效果非常卡頓。因此有了優化的必要。

利用工具定位問題

首先利用performance工具的的錄制功能錄制一段操作過程。
點擊左上角的黑色原點開始錄制。錄制過程中,多次滑動周日歷即可。然后大約5~10秒點擊stop按鈕停止錄制。

錄制結果如圖。

從上圖中我們可以發現以下問題:

1、 窗格中出現了紅幀。出現紅幀表示頁面已經超負荷,會出現卡頓,響應緩慢等現象。
2、 大量的黃色區域,黃色區域越大,表示JavaScript的運行過程中的壓力也越大。
3、 高額的內存占用,以及不正常的波動曲線(藍色)。詳細信息可以在上圖中的JS Heap中查看。26.6 ~ 71.6M

我們可以在Main中觀察到當前時刻的函數調用棧詳情。當出現紅幀,選中紅幀區域,Main區域發現變化,變為當前選擇時段的函數調用棧詳情。我們會發現函數調用棧最上層有一個紅色三角形。點擊會在下面的Summary里發現對應的信息以及警告。如下圖中的Warning: Recuring handler took 86.69 ms

4、 層級很高的函數調用棧。查看紅色區域的函數調用棧,我們會發現大量的react組件方法被重復調用。

一步一步開始優化

從上面的分析就可以簡單看出,雖然實現了非常復雜的功能,看上去很厲害的樣子,其實內部非常糟糕。幾乎可以作為react用法的反面教材了。

優化分析1

在上面的函數調用棧中,我們發現有一個方法出現的次數非常多,那就是receiveComponent。因此可以預想到某個組件里肯定使用了receiveComponent相關的生命周期的方法。檢查代碼,確實發現了幾處componentWillReceiveProps的使用。

// 每一次更新狀態都會刷新一次,導致了大量的計算
componentWillReceiveProps(nextProps) {
    this.setState({
        navProcess: getNavigation(nextProps.currentData)
    })
}

剛開始學習react時可能會認為生命周期是一個學習難點,我們不知道什么情況下去使用它們。慢慢的隨著經驗的增加,才發現,生命周期方法是萬萬不能輕易使用的。特別是與props/state改變,與組件重新渲染相關的幾個生命周期,如componentWillReceivePropsshouldComponentUpdate componentWillUpdate等。這個實際案例告訴我們,他們的使用,會造成高額的性能消耗。所以不到萬不得已,不要輕易使用他們。

曾經看到過一篇英文博文,分析的是寧愿多幾次render,也不要使用shouldComponentUpdate來優化代碼。但是文章地址找不到,如果有其他看過的朋友請在評論里留言分享一下,感謝

而只有componentDidMount是非常常用的。

上面幾行簡單的代碼,暴露了一個非常恐怖的問題。一個是使用了生命周期componentWillReceiveProps。而另一個則是在props改變的同時,還修改了組件的state。我們知道當props在父級被改變時會造成組件的重新渲染,而組件內部的state的改變同樣也會造成組件的重新渲染,因此這幾句簡單的代碼,讓組件發生了很多次冗余的渲染。

因此優化的方向就朝這兩個方向努力。首先不能使用componentWillReceiveProps,其次我發現navProcess其實可以在父級組件中計算,并通過props傳遞下來。所以優化后的代碼如下:

function Index(props) {
    const { currentD, currentM, selectD, setDate, loading, error, process, navProcess } = props;
    return (
        
{ loading ? null : error ? : } {loading ? : null}
) } export default withWrapped(Index);

意外的驚喜是發現該組件最終優化成為了一個無狀態組件,輕裝上陣,完美。

這樣優化之后,重新渲染的發生少了好幾倍,運行壓力自然減少很多。因此當滑動周日歷時已經不會有紅幀發生了。但是月日歷由于DOM節點更多,仍然存在問題,因此核心的問題還不在這里。我們還得繼續觀察。

優化分析2

在函數調用棧中我們可以很明顯的看到一個名為ani的方法。而這個方法是我自己寫的運動實現。因此我得重點關注它的實現中是不是存在什么問題。仔細瀏覽一遍,果然有問題。

發現在ani方法的回調中,調用了2次setDate方法。

// 導致頂層高階組件多一次渲染,下層多很多次渲染
setDate(newCur, 0);
setDate({ year: newCur.year, month: newCur.month }, 1)

該setDate方法是在父級中定義用來修改父級state的方法。他的每一次調用都會引發由上自下的重新渲染,因此多次調用的代價是非常大的。所以我將要面臨的優化就是想辦法將這兩次調用合并為一次。

先看看優化以前setDate方法的定義是如何實現的。我想要通過不同的number來修改不同的state屬性。但是沒有考慮如果需要修改多個呢?

setDate = (date, number) => {
    if (number == 0) {
        this.setState({
            currentD: date,
            currentM: { year: date.year, month: date.month }
        })
    }

    if (number == 1) {
        this.setState({
            currentM: date
        })
    }

    if (number == 2) {
        _date = date;
        _month = { year: date.year, month: date.month };
        this.setState({
            currentD: _date,
            currentM: _month,
            selectD: _date
        })
        this.process(date);
    }
}

修改該方法為,傳遞一個對象字面量進去進行修改

setDate = (options) => {
    const state = { ...this.state, ...options };
    if (options.selectD) {
        _date = options.selectD;
        _month = { year: _date.year, month: _date.month }
        state.currentD = _date;
        state.currentM = _month;
        this.process(_date, state);
    } else {
        this.setState(state);
    }
}

該方法有兩處優化,第一處優化是傳入的參數調整,想要修改那一個就直接傳入,用法類似setState。第二處優化是在this.process方法中只調用一次this.setState,總之這樣處理的目的都是統一的,當想要數據修改時只發生一次渲染。而之前的方法會導致3次甚至多次渲染。這樣優化之后,性能自然會提升很多。

優化分析3

但是優化并沒有結束,因為再錄制一段查看,仍然會發現紅幀出現。
進一步查看Calendar組件,發現每一次滑動切換,都會發生4次渲染。肯定有問題。

我的目的是最多發生兩次無法避免的渲染。多余的肯定是因為代碼的問題導致的冗余渲染。因此繼續查看代碼。

發現在遞歸調用ani方法時,this.timer并沒有被及時取消。

// 我的目的是每一次遞歸會調用一次requestAnimationFrame與cancelAnimationFrame
// 但是這樣寫只會在遞歸結束時調用一次cancelAnimationFrame
if (offset == duration) {
    callback && callback();
    cancelAnimationFrame(this.timer);
} else {
    this.timer = requestAnimationFrame(ani);
}

因此修改如下:

ani = () => {
    ....
    if (offset == duration) {
        callback && callback();
    } else {
        this.timer = requestAnimationFrame(ani);
    }
    cancelAnimationFrame(this.timer);
}

這樣優化之后,發現內存占用下降一些,但是紅幀仍然存在。看來計算量并沒有下降。繼續優化。

優化分析4

發現Calendar組件中,根據props中的curDate,curMonth計算而來的weekInfo與monthInfo被寫在了該組件的state中。由于state中數據的變化都會導致重新渲染,而我發現在代碼中有多處對他們進行修改。

componentDidMount() {
    const { curDate, curMonth } = this.props

    this.setState({
        weekInfo: calendar.get3WeekInfo(curDate),
        monthInfo: calendar.get3MonthInfo(curMonth)
    })

    this.setMessageType(curDate, 0);
    this.setMessageType(curMonth, 1);
}

其實這種根據props中的參數計算而來的數據是萬萬不能寫在state中的,因為props數據的變化也會導致組件刷新重新渲染,因此一個數據變化就會導致不可控制的多次渲染。這個時候更好的方式是直接在render中計算。因此優化如下:

render() {
    ...
    let info = type == 0 ? c.get3WeekInfo(curDate) : c.get3MonthInfo(curMonth);
    ...
}

優化結果如下圖

與第一張圖對比,我們發現,運動過程中出現的紅幀沒有了。二是窗格中黃色區域大量減少,表示js的計算量減少很多。三是內存占用大幅降低,從最高的71M減少到了33M。內存的增長也更加平滑。

后續的優化大致目的都是一樣。不再贅述。

最后總結一下:

盡量避免生命周期方法的使用,特別是與狀態更新相關的生命周期,使用時一定要慎重。

能通過props重新渲染組件,就不要在額外添加state來增加渲染壓力。

一切的優化方向就是在實現功能的前提下減少重新渲染的發生。

這其中涉及到的技巧就需要大家在實戰中慢慢掌握了。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92094.html

相關文章

  • 2017-07-08 前端日報

    摘要:前端日報精選精讀與提案知乎專欄第期認識引擎記錄一次利用工具進行性能優化的真實案例簡書中的使用規則教程繼承的實現方法個人文章中文譯組件渲染性能探索個人文章周刊第期表單性能的改進實踐知乎專欄簡單可重用的圖表庫知乎專欄 2017-07-08 前端日報 精選 精讀 TC39 與 ECMAScript 提案 - 知乎專欄【第989期】認識 V8 引擎記錄一次利用 Timeline/Perform...

    王巖威 評論0 收藏0
  • JavaScript 啟動性能瓶頸分析與解決方案

    摘要:啟動性能瓶頸分析與解決方案翻譯自的,從屬于筆者的前端入門與工程實踐。我們必須要清醒地認識到全面評測以挖掘出真正性能瓶頸的重要性。這可能是最佳的方式了,類似于這樣的模式鼓勵基于路由的分組,目前被與廣泛使用。 JavaScript 啟動性能瓶頸分析與解決方案 翻譯自 Addy Osmani 的 JavaScript Start-up Performance,從屬于筆者的Web 前端入門與工...

    SQC 評論0 收藏0
  • 使用Performance對頁面進行分析優化(實戰篇)

    摘要:在此,我們可以使用懶加載方式對其進行優化,僅展示其對應類型的圖,避免了不必要的資源浪費和計算時間。 這篇文章將介紹下實際使用performance對頁面進行優化的過程。總的來說,chrome performance工具讓我們更方便的發現在代碼運行過程中的問題在哪里,便于對一些可能注意不到的問題進行定位、分析和優化。原文首發于個人博客 渲染優化 首先,我們對進入整個詳情頁進行分析,整個頁...

    luodongseu 評論0 收藏0
  • 使用性能API快速分析web前端性能

    摘要:性能時間線以一個統一的接口獲取由和所收集的性能數據。瀏覽器支持下表列舉了當前主流瀏覽器對性能的支持,其中標注星號的內容并非來自于性能工作小組。 頁面的性能問題一直是產品開發過程中的重要一環,很多公司也一直在使用各種方式監控產品的頁面性能。從控制臺工具、Fiddler抓包工具,到使用DOMContentLoaded和document.onreadystatechange這種侵入式java...

    mj 評論0 收藏0
  • React16性能改善原理一

    摘要:接下來看下偽代碼調度算法偽代碼原來這段寫的匆忙且不好,重新更新了一篇講調度算法的大概實現性能改善的原理二。 問題背景 React16 更新了底層架構,新架構主要解決更新節點過多時,頁碼卡頓的問題。譬如如下代碼,根據用戶輸入的文字生成10000行數據,用戶輸入框會出現卡頓現象。 class App extends React.Component { constructor( prop...

    zhangqh 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<