咱們老是或多或少的據說過直接操做DOM是低效和緩慢的。然而,咱們幾乎沒有可用的數據來支持這個觀點。關於React虛擬DOM的使人愉悅的地方在於web開發過程當中,它採用了更加高效的方式來更新view層。javascript
咱們把使用React的其餘好處姑且放到一邊,例如單項綁定和組件化。本節我講詳細的討論一下虛擬DOM,隨後公正的抉擇爲何使用React而不是其餘UI庫(或者任何UI庫都不使用)。java
在反應式的系統中兩個最重要的idea應該是事件驅動和對數據變化的響應。react
DOM用戶接口組件有內部狀態,當不管什麼時候有狀況發生變化的時候,更新瀏覽器並非像簡單的從新生成DOM那麼簡單。舉個例子,若是Gmail曾經這麼作的話,由於瀏覽器窗口爲了顯示新的信息,須要不斷的刷新整個頁面,若是你正在寫郵件的話,全部的都會被清除,你必定會常常惱怒不已。程序員
DOM的這種狀態方式決定了爲何咱們須要一個用戶界面庫,由於這些庫提供了一些解決方案,例如鍵/值 觀察(在Ember庫中使用了此方法),或者髒值檢測(Angular使用了此方法)。UI庫能夠觀察數據模型的改變,而後在改變發生的時候只改變對應的部分DOM,或者觀察DOM改變,而後更新數據模型。web
這種觀察和更新的模式叫作雙向綁定,這種方式經常讓與用戶界面的工做更加複雜和讓人困惑。算法
React的虛擬DOM與其餘庫的不一樣之處在於從程序員的角度看,這種模式更加的簡單。你只須要寫純javascript,而後更新React組件,React將爲你更新DOM。數據綁定並無和應用程序攪和在一塊兒。瀏覽器
React使用單向數據綁定使得事情變得更加簡單,每一次在ReactUI的input域中輸入內容,React並不直接改變狀態。相反,React更新數據模型,隨後引發UI更新,你輸入的文字將在域中出現。babel
關於虛擬DOM的不少演講和文章都指出,儘管如今jiavascript的引擎已經很快了,可是讀取和寫入瀏覽器的DOM仍是很慢,app
這不是特別的準確。DOM是很快的。增長和去除DOM節點就是設置一些javascript對象的屬性,這纔是簡單的操做,這並非須要作不少的工做。dom
真正慢的地方自在於,每次DOM改變的時候,都須要在瀏覽器中進行渲染。每一次DOM改變的時候,瀏覽器都須要從新計算CSS,進行佈局處理,而後從新渲染頁面。這都須要時間。
瀏覽器的開發者持續不斷的工做來縮短渲染頁面的時間。最關鍵的須要完成的事情是最小化DOM改變,而後批處理DOM變化,在必要的時候才從新渲染頁面。(目前原生瀏覽器仍是沒法作到)
這種批處理DOM改變的策略,把咱們提高到了一個更加抽象的層次,這也是React虛擬DOM背後的idea。
與真實DOM類似,虛擬DOM也是節點樹,以對象的形式列出內容,屬性。React的render方法從React組建中建立節點樹,由於動做改變等引發數據模型變化的時候,React更新節點樹。
每次React app內部的數據改變,用戶界面的虛擬DOM都會構建。
這裏就是最有趣的地方,在React中更新瀏覽器DOM須要三步: 1. 每次數據模型變化的時候,虛擬DOM節點樹都會從新構建。 2. React依賴某個算法(稱之爲diff算法)來與上一個虛擬DOM節點數進行比較,只有在不一樣的狀況下才從新進行計算。 3.全部的變化要通過批處理,完成以後,真實DOM才進行更新。
有人認爲只要有一點改變就從新構造整個虛擬DOM節點樹有點浪費,可是他沒有說起一個事實,React在內存中存儲有兩個虛擬DOM樹。
可是,真實狀況是渲染虛擬DOM老是比直接渲染瀏覽器DOM快。這種論斷與你使用的瀏覽器也沒多大的關係。
我不會作一些基準測試,由於已經有不少開發者建立了不少測試來搞清楚React虛擬DOM方法是否比原生的DOM渲染更加快速。可是頻繁的結論顯示彷佛不是這樣,可是由於不少測試都是不實際的,因此這些測試結果也可有可無。
簡單來講,虛擬DOM就是把全部瀏覽器爲了最小化DOM操做,這些對於開發者來講透明的操做進行了抽象。這層額外的抽象的缺點就是增長了CPU的開銷。
這裏有一個"hello,world"的例子,使用了原生的DOM操做:
隨後咱們在React中作相同的事情。在這裏請注意咱們須要包含React,React DOM 和babel,其中babel負責把在render方法中的類XML的代碼進行轉換成原生的javascript。
結果顯示,本地方法更加的快速。這並非開玩笑,讓咱們看一下證據。
這裏是加載和渲染真實DOM的性能分析圖。(來源於Chrome)
這裏是在一樣的瀏覽器中加載和展現React的"hello,world"應用時間線。
請注意本質上來講,事情是相同的。React比直接操做DOM慢,並且慢了不少。那麼,與jQuery比又如何呢?
從分析圖中,咱們能夠看到,jQuery進行展現最簡單的hello,world的應用比原生的純javascript滿了50毫秒,可是jQuery版本和原聲版本都是React的3倍。
因此,很清晰,若是要說哪個更快,原生的javascript和jQuery無疑略勝一籌。
可是,使用庫老是要比不使用庫慢一些,這顯然是再正常不過了,在內存裏進行構建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批處理以後只渲染一遍無疑是高效了不少。