爲何Vue3不使用時間切片(Time Slicing)

翻譯自Vuejs issue中尤大的回答:原文地址vue

在Web應用程序中,丟幀(janky)更新一般是因爲同步的高CPU時間和原生DOM的更新形成的。git

時間切片是在CPU工做期間保持應用響應的一種嘗試,但它隻影響CPU工做。DOM的刷新必須是同步的,以確保最終DOM狀態的一致性。github

因此,想象兩種丟幀更新的場景:數組

  1. CPU工做時間在16ms之內,可是須要操做大量的原生DOM更新操做(例如,掛在大量新的DOM內容)。無論你有沒有使用時間切片,應用依舊會感受到掉幀。
  2. CPU任務很是繁重,須要超過16ms的時間。從理論上講,時間切片開始發揮做用了。然而,HCI的研究代表,除非它在進行動畫,不然對於正常的用戶交互,大多數人對於100毫秒內的更新是感受不到有什麼不一樣的。

也就是說,只有在頻繁進行超過100ms的純CPU任務更新時,時間切片才實際有用。緩存

有趣的地方在於,這樣的場景更常常地發生在React中,由於:markdown

  1. React的虛擬DOM操做(reconciliation )天生就比較慢,由於它使用了大量的Fiber架構;架構

  2. React使用JSX來渲染函數相對較於用模板來渲染更加難以優化,模板更易於靜態分析。併發

  3. React Hooks將大部分組件樹級優化(即防止沒必要要的子組件的從新渲染)留給了開發人員,開發人員在大多數狀況下須要顯式地使用useMemo。並且,無論何時React接收到了children屬性,它幾乎總要從新渲染,由於每次的子組件都是一棵新的vdom樹。這意味着,一個使用Hook的React應用在默認配置下會過分渲染。更糟糕的是,像useMomo這類優化不能輕易地自動應用,由於:框架

    1. 它須要正確的deps數組;
    2. 盲目地任意使用它可能會阻塞本該進行的更新,相似與PureComponent

    不幸的是,大多數開發人員都很懶,不會積極地優化他們的應用。因此大多數使用Hook的React應用會作不少沒必要要的CPU工做。dom

相比之下,Vue就上面的問題作一下比較:

  1. 本質上更簡單,所以虛擬DOM操做更快(沒有時間切片-> 沒有fiber-> 更少的開銷);

  2. 經過分析模板進行了大量的AOT優化,減小了虛擬DOM操做的基本開銷。Benchmark顯示,對於一個典型的DOM代碼塊來講,動態與靜態內容的比例大約是1:4,Vue3的原生執行速度甚至比Svelte更快,在CPU上花費的時間不到React的1/10。

  3. 智能組件樹級優化經過響應式跟蹤,將插槽編譯成函數(避免子元素重複渲染)和自動緩存內聯句柄(避免內聯函數重複渲染)。除非必要,不然子組件永遠不須要從新渲染。這一切不須要開發人員進行任何手動優化。

    這意味着對於同一個更新,React應用可能形成多個組件從新渲染,但在Vue中大部分狀況下只會致使一個組件從新渲染。

默認狀況下, Vue3應用比React應用花費更少的CPU工做時間, 而且CPU工做時間超過100ms的機會大幅度減小了,除非在一些極端的狀況下,DOM可能成爲更主要的瓶頸。

如今,時間切片或併發模式帶來了另外一個問題:由於框架如今安排和協調了全部更新,它在優先級、失效、從新實例化等方面產生了大量額外的複雜性。全部這些邏輯處理都不可能被tree-shaken,這將致使運行時基線的大小膨脹。即便包含了Suspense和全部的tree-shaken,Vue 3的運行時仍然只有當前React + React DOM的1/4大小。

注意,這並非說併發模式是一個很差的主意。它提供一個有趣的新方法解決某一類問題(尤爲是相關協調異步狀態轉換),但時間切片(做爲併發的一個子特性)特別解決了React中比其餘框架更突出的問題,同時也帶來了成本。對於Vue 3來講,這種權衡彷佛是不值得的。

相關文章
相關標籤/搜索