目錄
1、什麼是Diff演算法
首頁 web前端 js教程 React中Diff演算法是什麼? Diff演算法的策略及實現

React中Diff演算法是什麼? Diff演算法的策略及實現

Sep 28, 2018 pm 05:27 PM
html html5 javascript react.js 前端

本篇文章帶給大家的內容是關於React中Diff演算法是什麼? Diff演算法的策略及實現,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

1、什麼是Diff演算法

  • 傳統Diff:diff演算法即差異查找演算法;對於Html DOM結構即為tree的差異查找演算法;而對於計算兩顆樹的差異時間複雜度為O(n^3),顯然成本太高,React不可能採用這種傳統演算法;

  1. ## React Diff:

  2. 之前說過,React採用虛擬DOM技術實現對真實DOM的映射,即React Diff演算法的差異查找實質是對兩個JavaScript物件的差異查找;

基於三個策略:
  • Web UI 中DOM 節點跨層級的移動操作特別少,可以忽略不計。 (tree diff)

    擁有相同類別的兩個元件將會產生相似的樹狀結構,擁有不同類別的兩個元件將會產生不同的樹狀結(component diff )

對於同一層級的一組子節點,它們可以透過唯一id 進行區分。 (element diff)React中Diff演算法是什麼? Diff演算法的策略及實現

  • 2、React Diff演算法解讀

首先需要明確,只有在React更新階段才會有Diff演算法的運用;

React中Diff演算法是什麼? Diff演算法的策略及實現

React更新機制:
    • ##React Diff演算法最佳化策略圖:

    • React更新階段會對ReactElement類型判斷而進行不同的操作;ReactElement類型包含三種即:文字、Dom、元件;
  1. 每個類型的元素更新處理方式:

  2. 自訂元素的更新,主要是更新render出的節點,做甩手掌櫃交給render出的節點的對應component去管理更新。
    text節點的更新很簡單,直接更新文案。
  • 瀏覽器基本元素的更新,分成兩塊:

#更新屬性,對比出前後屬性的不同,局部更新。並且處理特殊屬性,例如事件綁定。

子節點的更新,子節點更新主要是找出差異對象,找差異對象的時候也會使用上面的shouldUpdateReactComponent來判斷,如果是可以直接更新的就會遞歸呼叫子節點的更新,這樣也會遞歸查找差異物件。不可直接更新的刪除之前的物件或新增新的物件。之後根據差異物件操作dom元素(位置變動,刪除,新增等)。

  • 事實上Diff演算法只被調用於React更新階段的DOM元素更新過程;

    為什麼這麼說?

  • 1、 如果為更新文字類型
,內容不同就直接更新替換,不會呼叫複雜的Diff演算法:

 ReactDOMTextComponent.prototype.receiveComponent(nextText, transaction) {
    //与之前保存的字符串比较
    if (nextText !== this._currentElement) {
      this._currentElement = nextText;
      var nextStringText = '' + nextText;
      if (nextStringText !== this._stringText) {
        this._stringText = nextStringText;
        var commentNodes = this.getHostNode();
        // 替换文本元素
        DOMChildrenOperations.replaceDelimitedText(
          commentNodes[0],
          commentNodes[1],
          nextStringText
        );
      }
    }
  }
登入後複製
2、對於自訂元件元素:
    class Tab extends Component {
        constructor(props) {
            super(props);
            this.state = {
                index: 1,
            }
        }
        shouldComponentUpdate() {
            ....
        }
        render() {
            return (
                <p>
                    </p><p>item1</p>
                    <p>item1</p>
                
            )
        }
        
    }
    登入後複製
  • #需要明確的是,何為元件,可以說元件只不過是一段Html結構的包裝容器,並且具備管理這段Html結構的狀態等能力;
  • 如上述Tab元件:它的實質內容就是render函數傳回的Html結構,而我們所說的Tab類別就是這段Html結構的包裝容器(可以理解為一個包裝盒子);

    • 在React渲染機製圖中可以看到,自訂元件的最後結合React Diff優化策略一(不同類別的兩個元件具備不同的結構)

    • 3、基本元素:
    1. ReactDOMComponent.prototype.receiveComponent = function(nextElement, transaction, context) {
          var prevElement = this._currentElement;
          this._currentElement = nextElement;
          this.updateComponent(transaction, prevElement, nextElement, context);
      }
      
      ReactDOMComponent.prototype.updateComponent = function(transaction, prevElement, nextElement, context) {
          //需要单独的更新属性
          this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag);
          //再更新子节点
          this._updateDOMChildren(
            lastProps,
            nextProps,
            transaction,
            context
          );
      
          // ......
      }
      登入後複製

    2. 在this. _updateDOMChildren方法內部才呼叫了diff演算法。
    3. 3、React中Diff演算法的實作
    4. _updateChildren: function(nextNestedChildrenElements, transaction, context) {
          var prevChildren = this._renderedChildren;
          var removedNodes = {};
          var mountImages = [];
      
          // 获取新的子元素数组
          var nextChildren = this._reconcilerUpdateChildren(
            prevChildren,
            nextNestedChildrenElements,
            mountImages,
            removedNodes,
            transaction,
            context
          );
      
          if (!nextChildren && !prevChildren) {
            return;
          }
      
          var updates = null;
          var name;
          var nextIndex = 0;
          var lastIndex = 0;
          var nextMountIndex = 0;
          var lastPlacedNode = null;
      
          for (name in nextChildren) {
            if (!nextChildren.hasOwnProperty(name)) {
              continue;
            }
            var prevChild = prevChildren && prevChildren[name];
            var nextChild = nextChildren[name];
            if (prevChild === nextChild) {
              // 同一个引用,说明是使用的同一个component,所以我们需要做移动的操作
              // 移动已有的子节点
              // NOTICE:这里根据nextIndex, lastIndex决定是否移动
              updates = enqueue(
                updates,
                this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex)
              );
      
              // 更新lastIndex
              lastIndex = Math.max(prevChild._mountIndex, lastIndex);
              // 更新component的.mountIndex属性
              prevChild._mountIndex = nextIndex;
      
            } else {
              if (prevChild) {
                // 更新lastIndex
                lastIndex = Math.max(prevChild._mountIndex, lastIndex);
              }
      
              // 添加新的子节点在指定的位置上
              updates = enqueue(
                updates,
                this._mountChildAtIndex(
                  nextChild,
                  mountImages[nextMountIndex],
                  lastPlacedNode,
                  nextIndex,
                  transaction,
                  context
                )
              );
      
      
              nextMountIndex++;
            }
      
            // 更新nextIndex
            nextIndex++;
            lastPlacedNode = ReactReconciler.getHostNode(nextChild);
          }
      
          // 移除掉不存在的旧子节点,和旧子节点和新子节点不同的旧子节点
          for (name in removedNodes) {
            if (removedNodes.hasOwnProperty(name)) {
              updates = enqueue(
                updates,
                this._unmountChild(prevChildren[name], removedNodes[name])
              );
            }
          }
        }
      登入後複製

      4、基於中Diff的開發建議

  • 基於tree diff:

    #########在開發元件時,請注意保持DOM結構的穩定;即,盡可能少地動態操作DOM結構,尤其是移動操作。 ############當節點數過大或頁面更新次數過多時,頁面卡頓的現象會比較明顯。 ############這時可以透過 CSS 隱藏或顯示節點,而不是真的移除或新增 DOM 節點。 ##################基於component diff###:###
    1. 注意使用 shouldComponentUpdate() 來減少元件不必要的更新。

    2. 對於類似的結構應該盡量封裝成元件,既減少程式碼量,又能減少component diff的效能消耗。

  • 基於element diff

    1. #對於清單結構,盡量減少類似將最後一個節點移動到列表首部的操作,當節點數量過大或更新操作過於頻繁時,在一定程度上會影響React 的渲染效能。

    以上是React中Diff演算法是什麼? Diff演算法的策略及實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    HTML 中的表格邊框 HTML 中的表格邊框 Sep 04, 2024 pm 04:49 PM

    HTML 表格邊框指南。在這裡,我們以 HTML 中的表格邊框為例,討論定義表格邊框的多種方法。

    HTML 中的巢狀表 HTML 中的巢狀表 Sep 04, 2024 pm 04:49 PM

    這是 HTML 中巢狀表的指南。這裡我們討論如何在表中建立表格以及對應的範例。

    HTML 左邊距 HTML 左邊距 Sep 04, 2024 pm 04:48 PM

    HTML 左邊距指南。在這裡,我們討論 HTML margin-left 的簡要概述及其範例及其程式碼實作。

    HTML 表格佈局 HTML 表格佈局 Sep 04, 2024 pm 04:54 PM

    HTML 表格佈局指南。在這裡,我們詳細討論 HTML 表格佈局的值以及範例和輸出。

    HTML 輸入佔位符 HTML 輸入佔位符 Sep 04, 2024 pm 04:54 PM

    HTML 輸入佔位符指南。在這裡,我們討論 HTML 輸入佔位符的範例以及程式碼和輸出。

    HTML 有序列表 HTML 有序列表 Sep 04, 2024 pm 04:43 PM

    HTML 有序列表指南。在這裡我們也分別討論了 HTML 有序列表和類型的介紹以及它們的範例

    在 HTML 中移動文字 在 HTML 中移動文字 Sep 04, 2024 pm 04:45 PM

    HTML 中的文字移動指南。在這裡我們討論一下marquee標籤如何使用語法和實作範例。

    HTML onclick 按鈕 HTML onclick 按鈕 Sep 04, 2024 pm 04:49 PM

    HTML onclick 按鈕指南。這裡我們分別討論它們的介紹、工作原理、範例以及各個事件中的onclick事件。

    See all articles