爲什麼 Vue 3 裏沒有時間分片?
這是 2019 年發表在 vuejs/rfcs 裏的舊文,現在看起來也不過時。於是我把它翻譯成了中文。
譯文開始:
爲什麼從 Vue 3 裏移除了「時間分片」?
-
伊撒爾:我看到時間分片已經從 vue-next 代碼中移除了,但並沒有看到移除原因。有人知道爲什麼嗎?是因爲 Vue 3 不需要時間分片還是其他原因呢?
-
Akryum:主要原因是
-
複雜度太高了
-
收益太低了
-
Vue 3 太快了沒必要再加時間分片了
-
LinusBorg:注意這不意味着以後不會增加時間分片。我們會在未來重新考量投入產出比來決定是否重新實現時間分片。
-
尤雨溪:在 Web 應用中,「可中斷式更新」主要是由大量 CPU 計算加上覆雜 DOM 操作引起的。時間分片旨在讓應用在 CPU 進行大量計算時也能與用戶交互,但時間分片只能對大量 CPU 計算進行優化,無法優化複雜 DOM 操作,因爲要確保用戶正在操作的界面是最新的狀態纔行。
因此,我們可以考慮兩種不同的可中斷式更新的場景:
-
CPU 計算量不大,但 DOM 操作非常複雜(比如說你向頁面中插入了十萬個節點)。這種場景下不管你做不做時間分片,頁面都會很卡。
-
CPU 計算量非常大。理論上時間分片在這種場景裏會有較大收益,但是人機交互研究表明,除了動畫之外,大部分用戶不會覺得 10 毫秒和 100 毫秒有很大區別。
也就是說,時間分片只在 CPU 需要連續計算 100 毫秒以上的情況下才有較大收益。有意思的地方就出現了,在 React 經常會出現 100 毫秒以上的計算量,因爲
-
Fiber 架構的複雜性導致 React 的虛擬 DOM 協調效率較低,這是系統性的問題。
-
React 使用 JSX 導致它的渲染效率比 template 低,因爲 template 很容易做靜態分析和優化。
-
React Hooks 將大部分組件樹的優化 API 暴露給開發者,開發者很多時候需要手動調用 useMemo 來優化渲染效率。(譯註:這裏省略一些例子)這意味着 React 應用默認就有 render 過多的問題。更嚴重的是,這些優化在 React 裏很難自動化,因爲
-
這些優化要求開發者正確設置依賴數組
-
盲目添加 useMemo 會導致應該 render 的沒 render。
很不幸,大部分開發者都很懶,不會在每個地方都加上優化,因此大部分 React 應用都會有大量的沒必要的 CPU 計算工作。
對比較而言,Vue 解決了上述問題:
-
Vue 的架構裏沒有時間分片,也就沒有 Fiber,因此簡單了很多,這使得渲染可以更快。
-
Vue 通過分析 template、簡化協調過程,做了大量的 AOT 優化,性能測試結果表明大部分的 DOM 內容有 80% 屬於靜態內容,因此 Vue 3 的協調速度比 Svelte 快,花費的時間比 React 的 1/10 還少。
-
通過數據響應式追蹤,Vue 可以做到組件樹級別的優化,比如把插槽編譯爲函數以避免 children 的變化引發 re-render,比如自動緩存內聯事件處理函數以避免 re-render。Vue 3 可以做到在不借助開發者的任何手動優化的情況下,防止子組件在非必要的情況下 re-render。這意味着同樣一次更新,React 應用可能要 re-render 多個組件,而 Vue 應用很可能只 re-render 一個組件。
因此,在默認情況下,Vue 3 應用會比 React 應用少花費很多 CPU 時間,因而遇到 CPU 連續計算時間超過 100 毫秒的機會相當少,除非是極端情況。但大部分極端情況是 DOM 操作過於複雜,而不是 CPU 計算量太大。
另外,時間分片,或者說併發模式,給 React 帶來了另外一個問題:React 需要對所有更新任務進行調度和調和,這導致 React 還需要搞定任務優先級、任務失效處理、re-entry 等任務,這會使 React 變得更復雜,進而讓源碼的體積膨脹。就算 React 把 Suspense、Tree-shaking 等優化都加上,Vue 3 的運行時體積也只有 React + ReactDOM 的 1/4。
注意我並不是說併發模式是個餿主意,併發模式確實對處理某些問題提供了有意思的新途徑(尤其是在協調異步狀態轉換時 coordinating async state transitions),但是爲此而實現時間分片是否值得,還需要再三權衡,至少現在不值得 Vue 3 這樣做。
340 人點贊,8 人點踩。
-
伊撒爾:謝謝 @尤雨溪 的回覆,你總結得很不錯。
確實時間分片解決的問題並不多,只解決了很少一部分場景的問題,比如動畫和可視化。99% 的場景不需要時間分片,時間分片只會延長整個渲染時長。
React 有很多問題,我這裏補充一點,Fiber 的鏈表遍歷制約了 React 的 diff 算法、讓很多優化變得無法實施。
總得來說,Vue 3 對利弊的權衡對我很有說服力。
-
CyberAP:我認爲關於 100 毫秒的論述有些問題,因爲瀏覽器上有很多種不同的人機交互方式,按鈕點擊跟文字輸入、Tab 導航有很大的不同。顯然後兩種交互對時間要求更高,所以不能用一個時間來衡量所有交互方式。
-
尤雨溪:是的沒錯,但是
-
目前文字輸入、Tab 導航引發的 UI 更新都能很快完成,甚至都不會超過 16 毫秒。React 團隊提供的 demo 是刻意的,實際應用中很少這麼做。
-
就算文字輸入、Tab 導航引發的更新導致了大量的 CPU 計算,這種計算任務也是無法做到事件分片的。比如,一個在線的帶編譯器的文本編輯框,它需要在用戶輸入之後馬上完成編譯,時間分片根本不起作用,還不如使用防抖和節流來優化。
後面還有很多內容,我就不翻譯了。
大家面試的時候如果遇到類似的問題,可以用上面的內容來回答。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/wclLaG4dTjlWjqvmiMMEXg