React Diff 算法

React介紹

React是Facebook開發的一款JS庫,用於構建用戶界面的類庫。javascript

它採用聲明式範例,能夠傳遞聲明代碼,最大限度地減小與DOM的交互。java

特色:node

  1. 聲明式設計:React採用聲明範式,你能夠輕鬆描述你的應用
  2. 高效:React經過對DOM的模擬表現,最大限度地較少與DOM的交互。
  3. 靈活:React能夠與你所知道的庫或框架很好地工做。

在Web開發中,咱們總須要將變化的數據實時反應到UI上,這時就須要對DOM進行操做。而複雜或頻繁的DOM操做一般是性能瓶頸產生的緣由react

React爲此引入了虛擬DOM(Virtual DOM)的機制:算法

在瀏覽器端用Javascript實現了一套DOM API。基於React進行開發時全部的DOM構造都是經過虛擬DOM進行,每當數據變化時,React都會從新構建整個虛擬DOM樹,而後React將當前整個虛擬DOM樹和上一次的虛擬DOM樹進行對比,獲得虛擬DOM結構的區別,而後僅僅將須要變化的部分進行實際的瀏覽器DOM更新。瀏覽器

React Diff 算法

虛擬DOM做爲React的一大核心技術,瞭解其實現原理對於靈活應用有着很大幫助。性能優化

Javascript 虛擬DOM對象

在咱們項目中申明一個組件是這樣的:app

react.createElement('div', null, [
    // 建立一個img
    react.createElement('img', { src: "avatar.png", class: "profile" }),
    // 或者
    react.createElement('h1', null, [[user.firstName, user.lastName].join(' ')])
]);

最後,React都會轉換成相似這樣的基本對象:框架

{
    tagName: 'div',
    // 節點包含的屬性
    properties: {
        style: {
            color: '#fff'
        }
    },
    // 子節點
    children: [],
    // 節點的惟一標識
    key: 1
}

Javascript DOM節點樹

而後,React把Javascript DOM模對象 轉換成 Javascript DOM節點樹:dom

function create(vds, parent) {
  !Array.isArray(vds) && (vds = [vds]);
  // 若是沒有父元素則建立個fragment來當父元素
  parent = parent || document.createDocumentFragment();
  var node;
  vds.forEach(function (vd) {
    // 若是是文字節點
    if (isText(vd)) {
      // 建立文字節點
      node = document.createTextNode(vd.text);
    } else {
      // 建立元素
      node = document.createElement(vd.tag);
    }
    // 將元素塞入父容器
    parent.appendChild(node);
    // 看看有沒有子VNode,有孩子則處理孩子VNode
    vd.children && vd.children.length &&
      create(vd.children, node);
    // 看看有沒有屬性,有則處理屬性
    vd.properties &&
      setProps({ style: {} }, vd.properties, node);
  });
  return parent;
}

Diff Algorithm

如今咱們獲得的是Javascript 實現的虛擬DOM樹,在一個事件循環中,當state或者preps變化時,React會建立一個新的虛擬DOM樹,最後進行差別渲染。

diff(previous:VTree, current:VTree) -> PatchObject

React分三種情景:

a. 分層對比

layer


React 僅僅是嘗試把樹按照層級分解. 這完全簡化了複雜度, 並且也不會失去不少, 由於 Web 應用不多有 component 移動到樹的另外一個層級去。它們大部分只是在相鄰的子節點之間移動。

b. 基於key匹配

key

Keys是一個VNode的惟一識別,用於對兩個不一樣的VTree中的VNode作匹配的。經過key鎖定某個組件後,React就能夠直接對比這兩個差別DOM節點樹,複雜度爲O(n)。

因此這裏有個性能優化的技巧。假設你有一個key組件,他的key屬性爲foo,後續又將它改成bar,那麼React就會掉過DOM diff,同時徹底棄置div全部自元素,從頭渲染。在渲染大型子樹以免diff計算時,這樣的設計頗有用,由於咱們知道這種計算就是在浪費時間。

c. 基於自定義元素作優化

component

React提供自定義元素,因此匹配很簡單。React 只會匹配相同 class 的 component。

好比, 若是有個<Header><ExampleBlock>替換掉了,
React 會刪除掉 header 再建立一個example block。咱們不須要化寶貴的時間去匹配兩個不大可能有類似之處的 component。

結束

React在你調用 component 的 setState 方法的時候, 將其標記爲 dirty,到每個事件循環結束, React 檢查全部標記 dirty 的 component 從新繪製。每次調用 setState 會從新計算整個子樹.若是你想要提升性能, 儘可能少調用 setState。

最後, 你還有可能去掉一些子樹的從新渲染,若是你在 component 上實現function shouldComponentUpdate(nextProps, nextState) 的話,你根據 component 的前一個和下一個 props/state,告訴 React 這個 component 沒有更新, 也不須要從新繪製。

相關文章
相關標籤/搜索