日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

虚拟DOM Diff算法解析

發布時間:2023/12/6 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 虚拟DOM Diff算法解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

React中最神奇的部分莫過于虛擬DOM,以及其高效的Diff算法。這讓我們可以無需擔心性能問題而”毫無顧忌”的隨時“刷新”整個頁面,由虛擬DOM來確保只對界面上真正變化的部分進行實際的DOM操作。React在這一部分已經做到足夠透明,在實際開發中我們基本無需關心虛擬DOM是如何運作的。然而,作為有態度的程序員,我們總是對技術背后的原理充滿著好奇。理解其運行機制不僅有助于更好的理解React組件的生命周期,而且對于進一步優化React程序也會有很大幫助。

什么是DOM Diff算法

Web界面由DOM樹來構成,當其中某一部分發生變化時,其實就是對應的某個DOM節點發生了變化。在React中,構建UI界面的思路是由當前狀態決定界面。前后兩個狀態就對應兩套界面,然后由React來比較兩個界面的區別,這就需要對DOM樹進行Diff算法分析。

即給定任意兩棵樹,找到最少的轉換步驟。但是標準的的Diff算法復雜度需要O(n^3),這顯然無法滿足性能要求。要達到每次界面都可以整體刷新界面的目的,勢必需要對算法進行優化。這看上去非常有難度,然而Facebook工程師卻做到了,他們結合Web界面的特點做出了兩個簡單的假設,使得Diff算法復雜度直接降低到O(n)

  • 兩個相同組件產生類似的DOM結構,不同的組件產生不同的DOM結構;

  • 對于同一層次的一組子節點,它們可以通過唯一的id進行區分。

  • 算法上的優化是React整個界面Render的基礎,事實也證明這兩個假設是合理而精確的,保證了整體界面構建的性能。

    不同節點類型的比較

    為了在樹之間進行比較,我們首先要能夠比較兩個節點,在React中即比較兩個虛擬DOM節點,當兩個節點不同時,應該如何處理。這分為兩種情況:(1)節點類型不同 ,(2)節點類型相同,但是屬性不同。本節先看第一種情況。

    當在樹中的同一位置前后輸出了不同類型的節點,React直接刪除前面的節點,然后創建并插入新的節點。假設我們在樹的同一位置前后兩次輸出不同類型的節點。


    renderA:?<div?/>
    renderB:?<span?/>
    =>?[removeNode?<div?/>],?[insertNode?<span?/>]


    當一個節點從div變成span時,簡單的直接刪除div節點,并插入一個新的span節點。這符合我們對真實DOM操作的理解。

    需要注意的是,刪除節點意味著徹底銷毀該節點,而不是再后續的比較中再去看是否有另外一個節點等同于該刪除的節點。如果該刪除的節點之下有子節點,那么這些子節點也會被完全刪除,它們也不會用于后面的比較。這也是算法復雜能夠降低到O(n)的原因。

    上面提到的是對虛擬DOM節點的操作,而同樣的邏輯也被用在React組件的比較,例如:


    renderA:?<Header?/>
    renderB:?<Content?/>
    =>?[removeNode?<Header?/>],?[insertNode?<Content?/>]


    當React在同一個位置遇到不同的組件時,也是簡單的銷毀第一個組件,而把新創建的組件加上去。這正是應用了第一個假設,不同的組件一般會產生不一樣的DOM結構,與其浪費時間去比較它們基本上不會等價的DOM結構,還不如完全創建一個新的組件加上去。

    由這一React對不同類型的節點的處理邏輯我們很容易得到推論,那就是React的DOM Diff算法實際上只會對樹進行逐層比較,如下所述。

    逐層進行節點比較

    提到樹,相信大多數同學立刻想到的是二叉樹,遍歷,最短路徑等復雜的數據結構算法。而在React中,樹的算法其實非常簡單,那就是兩棵樹只會對同一層次的節點進行比較。如下圖所示:

    React只會對相同顏色方框內的DOM節點進行比較,即同一個父節點下的所有子節點。當發現節點已經不存在,則該節點及其子節點會被完全刪除掉,不會用于進一步的比較。這樣只需要對樹進行一次遍歷,便能完成整個DOM樹的比較。

    例如,考慮有下面的DOM結構轉換:

    A節點被整個移動到D節點下,直觀的考慮DOM Diff操作應該是


    A.parent.remove(A);?
    D.append(A);


    但因為React只會簡單的考慮同層節點的位置變換,對于不同層的節點,只有簡單的創建和刪除。當根節點發現子節點中A不見了,就會直接銷毀A;而當D發現自己多了一個子節點A,則會創建一個新的A作為子節點。因此對于這種結構的轉變的實際操作是:


    A.destroy();A?=?new?A();A.append(new?B());A.append(new?C());D.append(A);


    可以看到,以A為根節點的樹被整個重新創建。

    雖然看上去這樣的算法有些“簡陋”,但是其基于的是第一個假設:兩個不同組件一般產生不一樣的DOM結構。根據React官方博客,這一假設至今為止沒有導致嚴重的性能問題。這當然也給我們一個提示,在實現自己的組件時,保持穩定的DOM結構會有助于性能的提升。例如,我們有時可以通過CSS隱藏或顯示某些節點,而不是真的移除或添加DOM節點。

    由DOM Diff算法理解組件的生命周期

    上一篇文章中介紹了React組件的生命周期,其中的每個階段其實都是和DOM Diff算法息息相關的。例如以下幾個方法:

    • constructor: 構造函數,組件被創建時執行;

    • componentDidMount: 當組件添加到DOM樹之后執行;

    • componentWillUnmount: 當組件從DOM樹中移除之后執行,在React中可以認為組件被銷毀;

    • componentDidUpdate: 當組件更新時執行。

    為了演示組件生命周期和DOM Diff算法的關系,筆者創建了一個示例:https://supnate.github.io/react-dom-diff/index.html?,大家可以直接訪問試用。這時當DOM樹進行如下轉變時,即從“shape1”轉變到“shape2”時。我們來觀察這幾個方法的執行情況:

    瀏覽器開發工具控制臺輸出如下結果:


    C?will?unmount.
    C?is?created.
    B?is?updated.
    A?is?updated.
    C?did?mount.
    D?is?updated.
    R?is?updated.


    可以看到,C節點是完全重建后再添加到D節點之下,而不是將其“移動”過去。如果大家有興趣,也可以fork示例代碼:https://github.com/supnate/react-dom-diff?。從而可以自己添加其它樹結構,試驗它們之間是如何轉換的。

    相同類型節點的比較

    第二種節點的比較是相同類型的節點,算法就相對簡單而容易理解。React會對屬性進行重設從而實現節點的轉換。例如:


    renderA:?<div?id="before"?/>
    renderB:?<div?id="after"?/>
    =>?[replaceAttribute?id?"after"]


    虛擬DOM的style屬性稍有不同,其值并不是一個簡單字符串而必須為一個對象,因此轉換過程如下:


    renderA:?<div?style={{color:?'red'}}?/>
    renderB:?<div?style={{fontWeight:?'bold'}}?/>
    =>?[removeStyle?color],?[addStyle?font-weight?'bold']


    列表節點的比較

    上面介紹了對于不在同一層的節點的比較,即使它們完全一樣,也會銷毀并重新創建。那么當它們在同一層時,又是如何處理的呢?這就涉及到列表節點的Diff算法。相信很多使用React的同學大多遇到過這樣的警告:

    這是React在遇到列表時卻又找不到key時提示的警告。雖然無視這條警告大部分界面也會正確工作,但這通常意味著潛在的性能問題。因為React覺得自己可能無法高效的去更新這個列表。

    列表節點的操作通常包括添加、刪除和排序。例如下圖,我們需要往B和C直接插入節點F,在jQuery中我們可能會直接使用$(B).after(F)來實現。而在React中,我們只會告訴React新的界面應該是A-B-F-C-D-E,由Diff算法完成更新界面。

    這時如果每個節點都沒有唯一的標識,React無法識別每一個節點,那么更新過程會很低效,即,將C更新成F,D更新成C,E更新成D,最后再插入一個E節點。效果如下圖所示:

    可以看到,React會逐個對節點進行更新,轉換到目標節點。而最后插入新的節點E,涉及到的DOM操作非常多。而如果給每個節點唯一的標識(key),那么React能夠找到正確的位置去插入新的節點,入下圖所示:

    對于列表節點順序的調整其實也類似于插入或刪除,下面結合示例代碼我們看下其轉換的過程。仍然使用前面提到的示例:https://supnate.github.io/react-dom-diff/index.html?,我們將樹的形態從shape5轉換到shape6:

    即將同一層的節點位置進行調整。如果未提供key,那么React認為B和C之后的對應位置組件類型不同,因此完全刪除后重建,控制臺輸出如下:


    B?will?unmount.
    C?will?unmount.
    C?is?created.
    B?is?created.
    C?did?mount.
    B?did?mount.
    A?is?updated.
    R?is?updated.


    而如果提供了key,如下面的代碼:


    shape5:?function()?{
    ??return?(????<Root>
    ??????<A>
    ????????<B?key="B"?/>
    ????????<C?key="C"?/>
    ??????</A>
    ????</Root>
    ??);
    },

    shape6:?function()?{
    ??return?(????<Root>
    ??????<A>
    ????????<C?key="C"?/>
    ????????<B?key="B"?/>
    ??????</A>
    ????</Root>
    ??);
    },


    那么控制臺輸出如下:


    C?is?updated.
    B?is?updated.
    A?is?updated.
    R?is?updated.


    可以看到,對于列表節點提供唯一的key屬性可以幫助React定位到正確的節點進行比較,從而大幅減少DOM操作次數,提高了性能。

    小結

    本文分析了React的DOM Diff算法究竟是如何工作的,其復雜度控制在了O(n),這讓我們考慮UI時可以完全基于狀態來每次render整個界面而無需擔心性能問題,簡化了UI開發的復雜度。而算法優化的基礎是文章開頭提到的兩個假設,以及React的UI基于組件這樣的一個機制。理解虛擬DOM Diff算法不僅能夠幫助我們理解組件的生命周期,而且也對我們實現自定義組件時如何進一步優化性能具有指導意義。


    本文摘自異步社區,發表人:?xiangzhihong?,作品:《虛擬DOM Diff算法解析》,未經授權,禁止轉載。


    推薦閱讀

    2018年5月新書書單(文末福利)

    2018年4月新書書單

    異步圖書最全Python書單

    一份程序員必備的算法書單

    第一本Python神經網絡編程圖書





    長按二維碼,可以關注我們喲

    每天與你分享IT好文。


    異步圖書”后臺回復“關注”,即可免費獲得2000門在線視頻課程

    點擊查看原文,內容


    閱讀原文


    轉載于:https://blog.51cto.com/13127751/2134222

    總結

    以上是生活随笔為你收集整理的虚拟DOM Diff算法解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久久99国产精品一区 | 久操av | 18禁男女爽爽爽午夜网站免费 | 无码国产69精品久久久久同性 | 日本在线观看一区二区 | 黑人与亚洲人色ⅹvideos | 澳门久久 | 日韩一卡二卡三卡四卡 | 久久影院午夜理论片无码 | 欧美成人精品三级网站 | 欧美一级片一区 | 亚洲AV成人无码久久 | 色欧洲 | 亚洲成人1区 | 精品国产乱码久久久人妻 | 国产亚洲精品美女久久久久 | 色91在线 | www.白白色| 亚洲伊人影院 | 国产免费一区二区三区免费视频 | 艳母动漫在线播放 | 国产香蕉97碰碰碰视频在线观看 | www.午夜视频 | 日韩毛片免费看 | 日韩少妇视频 | 色先锋av| 奇米影视四色777 | 精品久久99 | 日韩影院一区二区 | 美女福利视频在线 | 精品一区二区三区不卡 | 在线免费观看污网站 | 人人射人人 | 日本高清不卡在线 | 三级不卡 | 91高清网站 | 16一17女人毛片 | 国产专区一区二区三区 | 玖玖热在线视频 | 欧美美女视频 | 一本一道久久 | 玖玖视频在线 | 91视频啪啪| 日韩操操操 | 国产成人久久精品流白浆 | 白浆一区 | 日韩爱爱片 | 久久久久黄色片 | 人妻视频一区二区三区 | 久久午夜场 | yy111122少妇光屁股影院 | 精品97人妻无码中文永久在线 | 91九色国产在线 | 婷婷亚洲视频 | 日日干,夜夜操 | xxx在线视频| 日韩无套无码精品 | 男男成人高潮片免费网站 | 9999视频| 久久国产一 | 午夜不卡影院 | 婷婷视频在线观看 | 亚洲日批视频 | 不用播放器看av | 人妻人人澡人人添人人爽 | 亚洲h动漫 | 亚洲国产成人av | 91操人| 午夜色网站 | 艳妇乳肉豪妇荡乳av无码福利 | 亚洲一区二区三区日韩 | 国产偷人妻精品一区 | 久久免费观看视频 | 欧美一区二区高清视频 | 樱花影院电视剧免费 | 免费看的av| 亚洲精品久久久久国产 | 久久99国产视频 | 国产在线精品自拍 | 精品欧美一区二区精品久久 | 亚洲天天视频 | 国产白丝在线观看 | 国产精品天天狠天天看 | 欧洲裸体片 | 精品免费视频一区二区 | 在线观看黄色的网站 | 开心激情深爱 | 91免费黄| 日本三级在线 | 日韩精品一区二区三区视频在线观看 | 午夜高清视频 | 6680新视觉电影免费观看 | 成人午夜福利视频 | 91看片网站| 人人妻人人澡人人爽欧美一区双 | 成人无码一区二区三区 | 麻豆视频污 | 蜜桃视频在线观看www | 中文字幕第315页 |