沐鳴總代理_如果沒有virtual dom,react會怎樣?

在2016年,如果react火起來的時候,沒有virtual dom,會怎樣?你還會選擇使用react嗎?這是一個歷史假設問題。但今天來看,這個問題卻非常有趣,因為,在經歷對react的狂熱追捧之後,我們也逐漸發現了一些virtual dom及其整個機制的缺陷,而這些缺陷,是否沒有virtual dom,就不會有?

Diff和Patch

很多人還分不清React渲染和diff的界限。virtual dom是對象樹,是用來表示組件樹的內存對象;fiber是在virtual dom的前提下,為每一個節點附加的任務機制對象;diff是對新老兩個virtual dom(內存對象)進行對比,對比過程中使用了fiber提供的任務機制,可以被中斷,中斷之後,要從頭來過;diff得到的結果是patch,用來表示哪些virtual dom節點發生了何種變化;更新渲染是實施patch過程,fiber上記錄了每一個virtual dom節點對應的真實DOM節點,每一個patch針對對應的DOM節點進行操作;diff過程可以中斷重來,patch渲染過程不能被中斷。

第一次渲染性能不佳

React在第一次渲染到界面時跟virtual dom的更新機制沒有半毛錢關係,根本沒法享受它帶來的性能優勢。相反,由於第一次渲染需要創建原始的virtual dom以及fiber體系,反而會浪費一定的性能,當需要進行大列表數據渲染時,這種浪費體現的更加明顯。

更新時並沒有想象中那麼強

virtual dom宣稱的對立面是,對一整塊DOM進行全部替換的更新方式,一次性更新整塊DOM需要消耗大量資源刪除原有DOM,創建新DOM,實施Reaint/Reflow過程,所以理論上virtual dom性能更好。但是,並不排除有的情況下,一次性替換整塊DOM會比用virtual dom的形式更新性能更好。當patch數量超過一定數額時,除了需要進行遍歷之外,每一次對小量的DOM進行操作,都可能帶來重繪過程,數量一多,那麼瀏覽器就需要完成n次重繪,造成卡頓,雖然一次性整塊替換DOM也會存在同樣問題。diff算法本身也存在性能損耗,fiber機制就是為了解決這個問題,但是實際上,fiber並沒有強化virtual dom的優勢,因為js是單線程的,即使異步操作,所以該做的計算一秒都少不了,在diff過程中,如果被中斷,就要從來一次,反而增加了時間,不過好在fiber的調度機制,可以在空閑的時候把能幹的先干,但是,該卡頓的還是會卡頓,這和fiber本身沒有關係,是js單線程決定的。

不用這套可以嗎?

不用virtual dom這套機制可以嗎?不就是想最小化更新DOM變化嗎,同樣的道理,我也有一個diff,也有一個類似patch的機制,直接在DOM上進行diff和patch,不需要virtual dom和fiber,以及它們所帶來的一切一切東西。


React更新過程

如果你仔細觀察上面這個圖,你就會發現,在diff階段,內存中需要保存兩個virtual dom,以及一套fiber,並最終產生一個patches列表。雖然是js內存對象,virtual dom所帶來的負擔其實也不輕,而且它實際上並非和真實DOM的結構完全一致,理論上會有更多層級。我們能否幹掉virtual dom,直接對DOM進行對比呢?

jqvm的更新過程

我在jQvm中,實現了這套更新邏輯,它不依賴virtual dom,也是有diff和patch兩個過程,但是其實是在同時完成的,diff是對兩個真實DOM結構進行對比,其中有一個是臨時DOM片段,更新完之後就會銷毀。直接對兩個DOM進行diff其實和react的diff在性能上差不太多,因為react diff雖有算法加持但深度更深,而直接DOM diff深度可能更深,但不會多出未知層級。在DOM diff過程中,發現差異馬上patch,而不是在找出所有不同后才patch,省了patch對象,也就是說,一次diff&patch,就完成了更新。當然,這不是說這種方式性能更好,不過非大規模更新情況下,這種更新方式也有明顯的優勢。

你可能還會問,既然如此,為啥不直接整塊替換呢?jqvm之前就是整塊替換的,遇到的問題是在input輸入時,一替換,就失焦了。所以,在原始DOM的基礎上進行更新,才是王道。

真正的意義在哪兒?

從上面可以看出,有沒有virtual dom,我們都可以完成視圖更新渲染,virtual dom不是必須的。那virtual dom的真正意義在哪裡?為什麼它可以吸引我們,讓我們狂熱不已?我覺得,最核心的點在於,它將視圖進行抽象為內存對象,抽象后的視圖與平台無關,無論是在web平台,還是移動設備平台上,都可以對virtual dom進行解釋,渲染成複合對應平台上的界面效果。而且它抽象的結果是對象(純對象),那麼就可以輕鬆在設備之間傳輸,比如服務端渲染到canvas(類似雲遊戲)。此外,有另外一種可能,將diff移出當前線程進行計算,啟動一個worker線程,或者webassembly,計算完之後,把patch傳回主線程,而在算的過程裏面,主線程在不產生衝突的情況下,界面還可以繼續更新另外一塊區域。這種想法好是好,但是馬上會遇到線程安全問題。

結語

對於web來說,virtual dom不是必須的。

來自:https://www.tangshuang.net/7942.html

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/10010