Svelte認為ReactJs的虛擬DOM是一個神話?

banq發表於2021-06-30

這是Svelte的觀點:像 React 這樣的框架的效能宣告只是胡說八道的營銷言論,JS UI 框架的價值一般不在於效能,而在於提供“宣告性的、狀態驅動的 UI 開發”,因為原始 JS/HTML/CSS 開發很糟糕,並且很容易做出糟糕的架構決策和編寫無法維護的義大利麵條式程式碼。這樣,無論您使用 Vue、React 還是 Angular,它對效能都沒有影響。
虛擬 DOM 都會在過程中增加額外的步驟,並且它們有成本。但是它也有用處,從總體上看,如果您手動操作 DOM,那麼您很可能只是交換樹的整個塊,而不是進行外科手術操作。因為手動管理所有這些手術操作很快就會變成一個繁瑣的、無法維護的混亂。但是,如果你這樣做,你會要求瀏覽器做更多的重新渲染,這將是代價高昂的。
另外,管理虛擬DOM是有開銷的,是的,如果您不按照框架期望的方式構建應用程式,您可能會遇到麻煩。
React 向我們展示了虛擬 DOM 可以為我們提供更好的程式設計模型並且仍然優於當時基於模板的框架的想法。React 試圖爭辯說直接 DOM 修改是昂貴的,並且使用虛擬 DOM 會產生更高的效能,這是胡說八道的主張。
 
React 最初的承諾是,您可以在每次狀態更改時重新渲染整個應用程式,而無需擔心效能。在實踐中,這並不準確。如果是這樣,就不需要像這樣的最佳化shouldComponentUpdate(這是告訴 React 何時可以安全地跳過元件的一種方式)。
即使使用shouldComponentUpdate,一次性更新整個應用程式的虛擬 DOM 也需要大量工作。不久前,React 團隊引入了一種叫做 React Fiber 的東西,它允許將更新分成更小的塊。這意味著(除其他外)更新不會長時間阻塞主執行緒,儘管它不會減少工作總量或更新所需的時間。
 

開銷從哪裡來?
最明顯的是,diffing 進行差異區分不是免費的。如果不先將新的虛擬 DOM 與之前的舊快照進行比較,就無法將更改應用於真實 DOM。拿前面的HelloMessage例子來說,假設name道具從“world”變成了“everyone”。

  • 兩個快照都包含一個元素。在這兩種情況下都是 a <div>,這意味著我們可以保留相同的 DOM 節點
  • 我們列舉舊屬性<div>和新屬性的所有屬性,以檢視是否需要更改、新增或刪除任何屬性。在這兩種情況下,我們都有一個屬性——aclassName的值為"greeting"
  • 下降到這個元素中,我們看到文字發生了變化,因此我們需要更新真實的 DOM

在這三個步驟中,在這種情況下只有第三個步驟有價值,因為 - 與絕大多數更新的情況一樣 - 應用程式的基本結構沒有改變。如果我們可以直接跳到第 3 步,效率會更高:

if (changed.name) {
  text.data = name;
}

(這幾乎就是 Svelte 生成的更新程式碼。與傳統的 UI 框架不同,Svelte 是一個編譯器,它在構建時就知道您的應用程式中的情況如何變化,而不是在執行時等待完成工作。)
 

元件本身帶來開銷
React 和其他虛擬 DOM 框架使用的差異演算法很快。可以說,更大的開銷在於元件本身。你不會寫這樣的程式碼......

function StrawManComponent(props) {
  const value = expensivelyCalculateValue(props.foo);

  return (
    <p>the value is {value}</p>
  );
}

...因為您會在value每次更新時不小心重新計算,無論是否props.foo已更改。
下面以看起來更良性的方式進行不必要的計算和分配也是非常常見的:

function MoreRealisticComponent(props) {
  const [selected, setSelected] = useState(null);

  return (
    <div>
      <p>Selected {selected ? selected.name : 'nothing'}</p>

      <ul>
        {props.items.map(item =>
          <li>
            <button onClick={() => setSelected(item)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

在這裡,我們在每次狀態更改時生成一個新的虛擬元素<li>陣列——每個元素都有自己的內聯事件處理程式——無論是否props.items已更改。除非您不健康地痴迷於效能,否則您不會對其進行最佳化。
 

駭客新聞網友觀點
一個 DOM直接修改比一個從虛擬VDOM再到DOM的修改流程要快,當然,如果您經常在每次更新時修改或插入 10,000 個元素,並且不想自己以某種方式批次處理這些元素,那麼虛擬VDOM 可能是效能上的勝利。如果數量通常更像是 1-10,則虛擬VDOM可能變成開銷負擔了。
有一些細微差別。如果您插入讀取和寫入操作,直接DOM修改仍然很昂貴。宣告式正規化允許框架批次處理相同型別的操作以防止雙重重繪。這是虛擬 DOM與jQuery的好處,但這並不是虛擬 DOM 獨有的好處。
虛擬DOM在針頭和大海撈針方面有一組不同的權衡:如果相對於一個不是很大DOM有很多修改,那麼每個修改變化的虛擬 DOM 開銷相對較低。但是,如果您只更新一棵非常大的樹中的單個元素,那麼每次修改都會產生大量開銷。
另一個需要注意的現代混淆因素是一些瀏覽器(特別是 Chrome)已經做到了,直接透過 DOM API 的修改不再導致重繪阻塞主執行緒。這意味著任何使用 JS API(而不是DOM API) 來衡量 UI 響應能力的效能基準測試都會有問題。
DOM 也是一種記憶體資料結構,並且還可以巧妙地將繪製命令批次傳送到硬體(GPU 或其他方式)。出於這個原因,我一直對像 React 這樣的框架的效能優勢持懷疑態度。
UI 框架(React 或 Angular)的最大好處是它將您的程式碼組織成一個定義的、可維護的模式。傳統上,JavaScript 是一門雜亂無章的程式語言,因此使用原始的 JS/HTML 開發很容易讓自己陷入困境並做錯事。
對我來說,Svelte 最重要的部分是它允許我以最優雅的方式編寫 Web 應用程式。編譯器優先的方法意味著我們可以選擇我們想要的任何語法,使整個過程儘可能愉快。
Svelte 最出色的部分是決定儘可能接近 JavaScript,因此任何瞭解 JS、HTML 和 CSS 的人都知道 svelte。匯入任何 vanilla JS 庫都是即插即用的,這意味著社群和生態系統跨越整個 JS 生態系統。不再需要 x-for-react 或 y-for-vue。
看到社群最近呈指數級增長真是太令人興奮了!!

相關文章