99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

React的diff算法是什么?

發(fā)布時間:2016-10-30 20:34  回復(fù):0  查看:2629   最后回復(fù):2016-10-30 20:34  

React提供一種聲明式API,使得我們不需要了解在每次更新時具體改變了什么。這使得開發(fā)應(yīng)用很簡單,但是React如何實(shí)現(xiàn)這一點(diǎn)并不明顯。本篇文章介紹Reactdiff算法為何在滿足高性能應(yīng)用要求時,React組件的更新是可預(yù)測的。

??前言

??在使用React時,我們首先思考創(chuàng)建React節(jié)點(diǎn)樹的render()方法,在下一次stateprops更新時,render()方法將返回另一個React元素樹,隨后React比較兩顆不同的React節(jié)點(diǎn)樹,并據(jù)此更新頁面視圖。

??已經(jīng)有一些基本方案解決在最小化操作下比較一顆React節(jié)點(diǎn)樹到新的React節(jié)點(diǎn)樹之間的不同。但是,最先進(jìn)的算法時間復(fù)雜度也是O(n^3),n是節(jié)點(diǎn)樹的元素?cái)?shù)量。

??diff算法

??如果在React中使用這些算法,展示1000個元素將要進(jìn)行10億次比較,這個性能太低;React實(shí)現(xiàn)了一個時間復(fù)雜度為O(n)的探索式算法,該算法基于兩點(diǎn)假設(shè):

??· 1.不同類型的元素生成不同的節(jié)點(diǎn)樹

??· 2.開發(fā)者通過key屬性的不同表現(xiàn)指出哪個子元素應(yīng)該渲染。

??實(shí)際上,這兩點(diǎn)假設(shè)對于大多數(shù)實(shí)踐是有效的。

??在比較兩個React節(jié)點(diǎn)樹時,React首先比較根元素,隨后的行為取決于根元素類型。

??根節(jié)點(diǎn)不同類型

??只要根節(jié)點(diǎn)類型不同,React就會銷毀舊節(jié)點(diǎn)樹,創(chuàng)建新節(jié)點(diǎn)樹。

??· 在銷毀節(jié)點(diǎn)樹時,舊的DOM節(jié)點(diǎn)會被銷毀,React組件實(shí)例觸發(fā)componentWillUnmount()方法。

??· 在創(chuàng)建新節(jié)點(diǎn)樹時,新的DOM節(jié)點(diǎn)被插入DOM樹,React組件實(shí)例依次觸發(fā)componentWillMount()方法和componentDidMount()方法。

??根節(jié)點(diǎn)類型不同,根節(jié)點(diǎn)下任何組件或元素節(jié)點(diǎn)都會被卸載,并且把其state銷毀,比如如下兩棵節(jié)點(diǎn)樹,diff后,卸載舊的Home組件,掛載一個新的Home組件實(shí)例:

??<div><Home />div>

??<a><Home />a>

??節(jié)點(diǎn)同類型

??當(dāng)比較兩個相同類型的React節(jié)點(diǎn)(包括組件和html元素)時(包括所有節(jié)點(diǎn),根節(jié)點(diǎn)和所有子節(jié)點(diǎn)),React比較兩者的屬性,不改變DOM節(jié)點(diǎn),只更新當(dāng)前節(jié)點(diǎn)需要改變的屬性,如:

??<div className="red" data-index="1">div>

??<div className="blue" data-index="1">div>

??對于如上兩個元素,React僅會改變當(dāng)前節(jié)點(diǎn)需要改變的className屬性。

??樣式更新

??如果節(jié)點(diǎn)需要更新樣式屬性,React僅會更新當(dāng)前節(jié)點(diǎn)需要改變的樣式屬性,如:

    <div style={{fontSize: '16px', color: '#aaa';}}  calssName="red"/>

    <div style={{fontSize: '18px', color: '#aaa';}}  calssName="red"/>

??React僅會更新當(dāng)前節(jié)點(diǎn)的font-size屬性值。

??React重復(fù)以上步驟,遞歸比較處理兩棵React節(jié)點(diǎn)樹.

??組件節(jié)點(diǎn)同類型

??前面的diff比較都是以html元素為例,但是對于組件,前文的理論依然適用,只是關(guān)于組件的比較,我們還需要了解更多內(nèi)容:當(dāng)某一組件更新了,組件實(shí)例還沒有改變,其組件狀態(tài)是通過渲染維護(hù)的。React更新當(dāng)前組件實(shí)例的(props)屬性以匹配新元素,并且調(diào)用當(dāng)前實(shí)例的componentWillReceiveProps()方法和componentWillUpdate()方法;然后調(diào)用render()方法并且使用diff算法遞歸比較已經(jīng)更新的節(jié)點(diǎn)樹和新返回的節(jié)點(diǎn)樹。

??遞歸比較子節(jié)點(diǎn)

??默認(rèn)地,在遞歸比較DOM節(jié)點(diǎn)的子節(jié)點(diǎn)時,React同時遍歷兩個子節(jié)點(diǎn)列表,當(dāng)發(fā)現(xiàn)不同時,立即做出改變。

??比如,需要在一個節(jié)點(diǎn)的子節(jié)點(diǎn)后插入一個子節(jié)點(diǎn),性能是很好的,比較如下兩棵節(jié)點(diǎn)樹:

    <ul>

        <li>first</li>

        <li>second</li>

    </ul>

 

    <ul>

        <li>first</li>

        <li>second</li>

        <li>third</li>

    </ul>

??React匹配ul節(jié)點(diǎn)的子節(jié)點(diǎn)列表,依次比較 <li>first</li><li>second</li> ,直到發(fā)現(xiàn)當(dāng)前元素缺少子節(jié)點(diǎn) <li>third</li> ,就立即插入一個 <li>third</li> 節(jié)點(diǎn)。

但是如果不是在末尾插入新的子節(jié)點(diǎn),而是在頭部插入:

    <ul>

        <li>first</li>

        <li>second</li>

    </ul>

 

    <ul>

        <li>third</li>

        <li>first</li>

        <li>second</li>

    </ul>

    React比較第一個子節(jié)點(diǎn)時,就發(fā)現(xiàn)不同,立馬改變該節(jié)點(diǎn),隨后全部子節(jié)點(diǎn)都需要改變,這樣的性能表現(xiàn)很不好。

??key屬性

??為了解決上面提到子節(jié)點(diǎn)比較的問題,React提供了key屬性,如果某子節(jié)點(diǎn)擁有key屬性,React會在原始子節(jié)點(diǎn)樹里使用key值來比較該子節(jié)點(diǎn),比如,對于如上實(shí)例,使用key屬性:

   <ul>

        <li key="1">first</li>

        <li key="2">second</li>

    </ul>

 

    <ul>

        <li key="3">third</li>

        <li key="1">first</li>

        <li key="2">second</li>

</ul>

對于如上這種結(jié)構(gòu),React會創(chuàng)建key值為3的節(jié)點(diǎn),而只是移動key值為12的節(jié)點(diǎn)。

??key屬性值與唯一性

??既然通過key值比較子節(jié)點(diǎn),那么很明顯,至少在子節(jié)點(diǎn)樹里,每個key值必須是唯一的,但是并不需要保證key值是全局唯一的。

??通常我們可以使用服務(wù)端返回的列表項(xiàng)數(shù)據(jù)中的idindex當(dāng)key值。

??diff算法的不足

??我們必須明白,React diff算法決定如何重新渲染組件,但這只是一個細(xì)節(jié)實(shí)現(xiàn),React可以對每一個action行為都重新渲染整個應(yīng)用,最后的視圖都是一樣的,我們在不斷地精煉探索式算法以提高應(yīng)用性能。

??目前的實(shí)現(xiàn)方式中,如前文的實(shí)例,我們知道在子節(jié)點(diǎn)間是可以不被重新渲染而只發(fā)生移動的,但是除此之外,子節(jié)點(diǎn)并不能被重用,算法將會重新渲染整個子節(jié)點(diǎn)樹。

??前文提到,Reactdiff算法是探索式的,基于兩點(diǎn)假設(shè),如果這兩點(diǎn)假設(shè)不滿足,性能就會降低:

??· 1.算法不會比較不同組件類型的子節(jié)點(diǎn)

??· 2.key值應(yīng)該是穩(wěn)定的,可預(yù)測的,唯一的。不穩(wěn)定的key值會產(chǎn)生很多不必要的重繪和子組件狀態(tài)的丟失。

 

文章來源:驚鴻三世的博客

您還未登錄,請先登錄

熱門帖子

最新帖子

?