爲什麼 Vue 3 裏沒有時間分片?

這是 2019 年發表在 vuejs/rfcs 裏的舊文,現在看起來也不過時。於是我把它翻譯成了中文。

譯文開始:


爲什麼從 Vue 3 裏移除了「時間分片」?

  1. 複雜度太高了

  2. 收益太低了

  3. Vue 3 太快了沒必要再加時間分片了

  1. CPU 計算量不大,但 DOM 操作非常複雜(比如說你向頁面中插入了十萬個節點)。這種場景下不管你做不做時間分片,頁面都會很卡。

  2. CPU 計算量非常大。理論上時間分片在這種場景裏會有較大收益,但是人機交互研究表明,除了動畫之外,大部分用戶不會覺得 10 毫秒和 100 毫秒有很大區別。

也就是說,時間分片只在 CPU 需要連續計算 100 毫秒以上的情況下才有較大收益。有意思的地方就出現了,在 React 經常會出現 100 毫秒以上的計算量,因爲

  1. Fiber 架構的複雜性導致 React 的虛擬 DOM 協調效率較低,這是系統性的問題。

  2. React 使用 JSX 導致它的渲染效率比 template 低,因爲 template 很容易做靜態分析和優化。

  3. React Hooks 將大部分組件樹的優化 API 暴露給開發者,開發者很多時候需要手動調用 useMemo 來優化渲染效率。(譯註:這裏省略一些例子)這意味着 React 應用默認就有 render 過多的問題。更嚴重的是,這些優化在 React 裏很難自動化,因爲

  4. 這些優化要求開發者正確設置依賴數組

  5. 盲目添加 useMemo 會導致應該 render 的沒 render。

很不幸,大部分開發者都很懶,不會在每個地方都加上優化,因此大部分 React 應用都會有大量的沒必要的 CPU 計算工作。

對比較而言,Vue 解決了上述問題:

  1. Vue 的架構裏沒有時間分片,也就沒有 Fiber,因此簡單了很多,這使得渲染可以更快。

  2. Vue 通過分析 template、簡化協調過程,做了大量的 AOT 優化,性能測試結果表明大部分的 DOM 內容有 80% 屬於靜態內容,因此 Vue 3 的協調速度比 Svelte 快,花費的時間比 React 的 1/10 還少。

  3. 通過數據響應式追蹤,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 人點踩。

  1. 目前文字輸入、Tab 導航引發的 UI 更新都能很快完成,甚至都不會超過 16 毫秒。React 團隊提供的 demo 是刻意的,實際應用中很少這麼做。

  2. 就算文字輸入、Tab 導航引發的更新導致了大量的 CPU 計算,這種計算任務也是無法做到事件分片的。比如,一個在線的帶編譯器的文本編輯框,它需要在用戶輸入之後馬上完成編譯,時間分片根本不起作用,還不如使用防抖和節流來優化。


後面還有很多內容,我就不翻譯了。

大家面試的時候如果遇到類似的問題,可以用上面的內容來回答。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/wclLaG4dTjlWjqvmiMMEXg