React虛擬DOM的好處

JingLMalan發表於2018-12-14

關於React提供的虛擬DOM的好處有一些困惑和誤解需要闡明。

我們總是或多或少的聽說過直接操作DOM是低效和緩慢的。然而,我們幾乎沒有可用的資料來支援這個觀點。關於React虛擬DOM的令人愉悅的地方在於web開發過程中,它採用了更加高效的方式來更新view層。

我們把使用React的其他好處姑且放到一邊,例如單項繫結和元件化。本節我講詳細的討論一下虛擬DOM,隨後公正的抉擇為什麼使用React而不是其他UI庫(或者任何UI庫都不使用)。

為什麼需要UI庫

在反應式的系統中兩個最重要的idea應該是事件驅動和對資料變化的響應。

DOM使用者介面元件有內部狀態,當無論何時有情況發生變化的時候,更新瀏覽器並不是像簡單的重新生成DOM那麼簡單。舉個例子,如果Gmail曾經這麼做的話,因為瀏覽器視窗為了顯示新的資訊,需要不斷的重新整理整個頁面,如果你正在寫郵件的話,所有的都會被清除,你一定會經常惱怒不已。

DOM的這種狀態方式決定了為什麼我們需要一個使用者介面庫,因為這些庫提供了一些解決方案,例如鍵/值 觀察(在Ember庫中使用了此方法),或者髒值檢測(Angular使用了此方法)。UI庫可以觀察資料模型的改變,然後在改變發生的時候只改變對應的部分DOM,或者觀察DOM改變,然後更新資料模型。

這種觀察和更新的模式叫做雙向繫結,這種方式常常讓與使用者介面的工作更加複雜和讓人困惑。

React的不同之處

React的虛擬DOM與其他庫的不同之處在於從程式設計師的角度看,這種模式更加的簡單。你只需要寫純javascript,然後更新React元件,React將為你更新DOM。資料繫結並沒有和應用程式攪和在一起。

React使用單向資料繫結使得事情變得更加簡單,每一次在ReactUI的input域中輸入內容,React並不直接改變狀態。相反,React更新資料模型,隨後引起UI更新,你輸入的文字將在域中出現。

DOM真的慢嗎?

關於虛擬DOM的很多演講和文章都指出,儘管現在jiavascript的引擎已經很快了,但是讀取和寫入瀏覽器的DOM還是很慢,

這不是特別的準確。DOM是很快的。增加和去除DOM節點就是設定一些javascript物件的屬性,這才是簡單的操作,這並不是需要做很多的工作。

真正慢的地方自在於,每次DOM改變的時候,都需要在瀏覽器中進行渲染。每一次DOM改變的時候,瀏覽器都需要重新計算CSS,進行佈局處理,然後重新渲染頁面。這都需要時間。

瀏覽器的開發者持續不斷的工作來縮短渲染頁面的時間。最關鍵的需要完成的事情是最小化DOM改變,然後批處理DOM變化,在必要的時候才重新渲染頁面。(目前原生瀏覽器還是無法做到)

這種批處理DOM改變的策略,把我們提升到了一個更加抽象的層次,這也是React虛擬DOM背後的idea。

虛擬DOM是怎麼工作的?

與真實DOM相似,虛擬DOM也是節點樹,以物件的形式列出內容,屬性。React的render方法從React組建中建立節點樹,因為動作改變等引起資料模型變化的時候,React更新節點樹。

每次React app內部的資料改變,使用者介面的虛擬DOM都會構建。

這裡就是最有趣的地方,在React中更新瀏覽器DOM需要三步: 1. 每次資料模型變化的時候,虛擬DOM節點樹都會重新構建。 2. React依賴某個演算法(稱之為diff演算法)來與上一個虛擬DOM節點數進行比較,只有在不同的情況下才重新進行計算。 3.所有的變化要經過批處理,完成之後,真實DOM才進行更新。

虛擬DOM慢嗎?

有人認為只要有一點改變就重新構造整個虛擬DOM節點樹有點浪費,但是他沒有提及一個事實,React在記憶體中儲存有兩個虛擬DOM樹。

但是,真實情況是渲染虛擬DOM總是比直接渲染瀏覽器DOM快。這種論斷與你使用的瀏覽器也沒多大的關係。

我們看一些資料

我不會做一些基準測試,因為已經有很多開發者建立了很多測試來搞清楚React虛擬DOM方法是否比原生的DOM渲染更加快速。但是頻繁的結論顯示似乎不是這樣,但是因為很多測試都是不實際的,所以這些測試結果也無關緊要。

簡單來說,虛擬DOM就是把所有瀏覽器為了最小化DOM操作,這些對於開發者來說透明的操作進行了抽象。這層額外的抽象的缺點就是增加了CPU的開銷。

這裡有一個"hello,world"的例子,使用了原生的DOM操作:

React虛擬DOM的好處

隨後我們在React中做相同的事情。在這裡請注意我們需要包含React,React DOM 和babel,其中babel負責把在render方法中的類XML的程式碼進行轉換成原生的javascript。

React虛擬DOM的好處

結果顯示,本地方法更加的快速。這並不是開玩笑,讓我們看一下證據。

這裡是載入和渲染真實DOM的效能分析圖。(來源於Chrome)

React虛擬DOM的好處

這裡是在同樣的瀏覽器中載入和展示React的"hello,world"應用時間線。

React虛擬DOM的好處

請注意本質上來說,事情是相同的。React比直接操作DOM慢,而且慢了很多。那麼,與jQuery比又如何呢?

React虛擬DOM的好處

React虛擬DOM的好處

從分析圖中,我們可以看到,jQuery進行展示最簡單的hello,world的應用比原生的純javascript滿了50毫秒,但是jQuery版本和原聲版本都是React的3倍。

所以,很清晰,如果要說哪一個更快,原生的javascript和jQuery無疑略勝一籌。

但是,使用庫總是要比不使用庫慢一些,這顯然是再正常不過了,在記憶體裡進行構建DOM,然後再進行真實的DOM操作更慢,也是很符合邏輯的情況。

廢話說多了,現在讓我們準確思考一下,怎麼使得虛擬DOM載入更快。

怎麼使用虛擬DOM

我的"hello world"專案對於React來說是不公平的,原因在於他們僅僅處理的是初次渲染頁面的效能比較。React設計的目的是用來更新網頁。

因為虛擬DOM的存在,每一次資料模型的改變都會觸發虛擬使用者介面的重新整理。這與其他庫進行直接的DOM更新是不一樣的。虛擬DOM實際上使用了更少的內訓,因為它不需要在記憶體中設定觀察者。

然而,每一次動作發生的時候,在記憶體中比較虛擬DOM也是低效的。這需要大量的CPU運算。

因為這個願意,React開發者在決定需要渲染什麼的時候並不是完全被動的。如果你知道特定的動作不會影響特定的元件,你可以告訴React不要去分析元件差別,這無疑可以大大節省資源,加快應用程式的效能。示範操作中的React程式是可以進行效能提升的。

真實情況是,沒辦法準確的知道虛擬DOM是否比直接進行DOM操作更快。因為這依賴於很多變數,尤其是和你怎麼優化程式密切相關。

這並不是革命性或者令人驚訝的事情,每個人使用的工具都是挺好的。React和虛擬DOM給予我們的,是用一種簡單的方式進行UI渲染,它提供給我們一種更加簡便的方式來更新瀏覽器。這種簡化可以大大釋放我們的腦力負擔,使得優化使用者介面更加的容易。這才是React真正好處所在的地方,如果處理得到,使用React,兼具效能和生產力,何樂而不為呢?

原文地址:www.accelebrate.com/blog/the-re…

作者: Chris Minnick

說明:原文有一處舉了一個100000個墨西哥玉米卷的例子,只是想說明不用每一次拿一個玉米卷,而是等待想拿的玉米卷確定之後然後在進行運輸到自己國家進行消費。本質上還是對映React的工作方式,原文閒的稍加囉嗦,有刪節。

總結: 本文核心有兩點:1.稍微介紹一下React的虛擬DOM和原生DOM的區別和聯絡。2.文末點出,虛擬DOM如果處理得到,是可以處理好效能問題的,但是React的真正好處在於,它的模組化思想,釋放了生產力。

顛覆:文中有幾個觀點需要重新審視,我們也經常聽說直接操作DOM是低效的,但是這種低效在什麼地方,似乎也沒有國內的開發者進行準確的資料論證比較,作者給出了它的解釋,直接操作DOM並不低效,低效的地方在於渲染頁面的過程繁雜浪費時間,相比於React批處理之後只渲染一遍無疑是高效了很多。

相關文章