深入理解react中的虛擬DOM、diff演算法

來源:互聯網
上載者:User

標籤:執行   rtu   做了   img   大量   pat   是什麼   http   www.   

文章結構:

  • React中的虛擬DOM是什嗎?
  • 虛擬DOM的簡單實現(diff演算法)
  • 虛擬DOM的內部工作原理
  • React中的虛擬DOM與Vue中的虛擬DOM比較

 

React中的虛擬DOM是什嗎?

    雖然React中的虛擬DOM很好用,但是這是一個無心插柳的結果。   

   React的核心思想:一個Component拯救世界,忘掉煩惱,從此不再操心介面。1. Virtual Dom快,有兩個前提1.1 Javascript很快

   Chrome剛出來的時候,在Chrome裡跑Javascript非常快,給了其它瀏覽器很大壓力。而現在經過幾輪你追我趕,各主流瀏覽器的Javascript執行速度都很快了。

   在 https://julialang.org/benchmarks/ 這個網站上,我們可以看到,JavaScript語言已經非常快了,和C就是幾倍的關係,和java在同一個量級。所以說,單純的JavaScript還是還是很快的。

  

1.2 Dom很慢

  當建立一個元素比如div,有以下幾項內容需要實現: HTML element、Element、GlobalEventHandler。簡單的說,就是插入一個Dom元素的時候,這個元素上本身或者繼承很多屬性如 width、height、offsetHeight、style、title,另外還需要註冊這個元素的諸多方法,比如onfucos、onclick等等。 這還只是一個元素,如果元素比較多的時候,還涉及到嵌套,那麼元素的屬性和方法等等就會很多,效率很低。

  比如,我們在一個空白網頁的body中添加一個div元素,如下所示:

       

  這個元素會掛載預設的styles、得到這個元素的computed屬性、註冊相應的Event Listener、DOM Breakpoints以及大量的properties,這些屬性、方法的註冊肯定是需要h耗費大量時間的。

   尤其是在js操作DOM的過程中,不僅有dom本身的繁重,js的操作也需要浪費時間,我們認為js和DOM之間有一座橋,如果你頻繁的在橋兩邊走動,顯然效率是很低的,如果你的JavaScript操作DOM的方式還非常不合理,那麼顯然就會更糟糕了。 

  而 React的虛擬DOM就是解決這個問題的! 雖然它解決不了DOM自身的繁重,但是虛擬DOM可以對JavaScript操作DOM這一部分內容進行最佳化

  

  比如說,現在你的list是這樣:

<ul><li>0</li><li>1</li><li>2</li><li>3</li></ul>

  你希望把它變成下面這樣:

<ul><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

  

  通常的操作是什麼? 

  先把0, 1,2,3這些Element刪掉,然後加幾個新的Element 6,7,8,9,10進去,這裡面就有4次Element刪除,5次Element添加。共計9次DOM操作

  

  那React的虛擬DOM可以怎麼做呢

  而React會把這兩個做一下Diff,然後發現其實不用刪除0,1,2,3,而是可以直接改innerHTML,然後只需要添加一個Element(10)就行了,這樣就是4次innerHTML操作加1個Element添加。共計5此操作,這樣效率的提升是非常可觀的。

  

2、 關於React

2.1 介面和設計

  在React的設計中,是完全不需要你來操作DOM的我們也可以認為,在React中根本就沒有DOM這個概念,有的只是Component。 

  當你寫好一個Component以後,Component會完全負責UI,你不需要也不應該去也不能夠指揮Component怎麼顯示,你只能告訴它你想要顯示一個香蕉還是兩個梨。

  隔離DOM並不僅僅是因為DOM慢,而也是為了把介面和業務完全隔離,操作資料的只關心資料,操作介面的只關心介面。比如在websocket聊天室的建立房間時,我們可以首先Component寫好,然後當擷取到資料的時候,只要把資料放在redux中就好,然後Component就動把房間添加到頁面中去,而不是你先拿到資料,然後使用js操作DOM把資料顯示在頁面上。 

  即我提供一個Component,然後你只管給我資料,介面的事情完全不用你操心,我保證會把介面變成你想要的樣子。所以說React的著力點就在於View層,即React專註於View層。你可以把一個React的Component想象成一個Pure Function,只要你給的資料是[1, 2, 3],我保證顯示的是[1, 2, 3]。沒有什麼刪除一個Element,添加一個Element這樣的事情。NO。你要我顯示什麼就給我一個完整的列表。

  另外,Flux雖然說的是單向的Data Flow(redux也是),但是實際上就是單向的Observer,Store->View->Action->Store(箭頭是資料流向,實現上可以理解為View監聽Store,View直接trigger action,然後Store監聽Action)。

  

2.2 實現

  那麼react如何?呢? 最簡單的方法就是當資料變化時,我直接把原先的DOM卸載,然後把最新資料的DOM替換上去。 但是,虛擬DOM哪去了? 這樣做的效率顯然是極低的。

  所以虛擬DOM就來救場了。

  那麼虛擬DOM和DOM之間的關係是什麼呢? 

  首先,Virtual DOM並沒有完全實現DOM,即虛擬DOM和真正地DOM是不一樣的Virtual DOM最主要的還是保留了Element之間的層次關係和一些基本屬性。因為真實DOM實在是太複雜,一個空的Element都複雜得能讓你崩潰,並且幾乎所有內容我根本不關心好嗎所以Virtual DOM裡每一個Element實際上只有幾個屬性,即最重要的,最為有用的,並且沒有那麼多亂七八糟的引用,比如一些註冊的屬性和函數啊,這些都是預設的,建立虛擬DOM進行diff的過程中大家都一致,是不需要進行比對的。所以哪怕是直接把Virtual DOM刪了根據新傳進來的資料重新建立一個新的Virtual DOM出來都非常非常非常快。(每一個component的render函數就是在做這個事情,給新的virtual dom提供input)。

   所以,引入了Virtual DOM之後,React是這麼乾的:你給我一個資料,我根據這個資料產生一個全新的Virtual DOM,然後跟我上一次產生的Virtual DOM去 diff,得到一個Patch,然後把這個Patch打到瀏覽器的DOM上去。完事。並且這裡的patch顯然不是完整的虛擬DOM,而是新的虛擬DOM和上一次的虛擬DOM經過diff後的差異化的部分。

  

  假設在任意時候有,VirtualDom1 == DOM1 (組織圖相同, 顯然虛擬DOM和真實DOM是不可能完全相等的,這裡的==是js中非完全相等)。當有新資料來的時候,我產生VirtualDom2,然後去和VirtualDom1做diff得到一個Patch(差異化的結果)。然後將這個Patch去應用到DOM1上,得到DOM2。如果一切正常,那麼有VirtualDom2 == DOM2(同樣是結構上的相等)

  

  這裡你可以做一些小實驗,去破壞VirtualDom1 == DOM1這個假設(手動在DOM裡刪除一些Element,這時候VirtualDom裡的Element沒有被刪除,所以兩邊不一樣了)。
然後給新的資料,你會發現產生的介面就不是你想要的那個介面了。

  

  最後,回到為什麼Virtual Dom快這個問題上
        其實是由於每次產生virtual dom很快,diff產生patch也比較快,而在對DOM進行patch的時候,雖然DOM的變更比較慢但是React能夠根據Patch的內容最佳化一部分DOM操作,比如之前的那個例子。

  重點就在最後,哪怕是我產生了virtual dom(需要耗費時間)哪怕是我跑了diff(還需要花時間)但是我根據patch簡化了那些DOM操作省下來的時間依然很可觀(這個就是時間差的問題了,即節省下來的時間 > 產生 virtual dom的時間 + diff時間)。所以總體上來說,還是比較快。

  

        簡單發散一下思路,如果哪一天,DOM本身的已經操作非常非常非常快了,並且我們手動對於DOM的操作都是精心設計最佳化過後的,那麼加上了VirtualDom還會快嗎
當然不行了,畢竟你多做了這麼多額外的工作

        但是那一天會來到嗎?
        誒,大不了到時候不用Virtual DOM。
註: 此部分內容整理自:https://www.zhihu.com/question/29504639/answer/44680878       虛擬DOM的簡單實現(diff演算法)目錄
  • 1 前言
  • 2 對前端應用狀態管理思考
  • 3 Virtual DOM 演算法
  • 4 演算法實現
    • 4.1 步驟一:用JS對象類比DOM樹
    • 4.2 步驟二:比較兩棵虛擬DOM樹的差異
    • 4.3 步驟三:把差異應用到真正的DOM樹上
  • 5 結語
  • 6 References

 

前言

  在上面一部分中,我們已經簡單介紹了虛擬DOM的答題思路和好處,這裡我們將通過自己寫一個虛擬DOM來加深對其的理解,有一些自己的思考。

  

對前端應用狀態管理思考

  維護狀態,更新視圖

  

              源碼地址: https://github.com/livoras/simple-virtual-dom參考文章:https://github.com/livoras/blog/issues/13    

      
  

  

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

深入理解react中的虛擬DOM、diff演算法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.