Heim  >  Artikel  >  Web-Frontend  >  Was ist der Diff-Algorithmus in React? Strategie und Implementierung des Diff-Algorithmus

Was ist der Diff-Algorithmus in React? Strategie und Implementierung des Diff-Algorithmus

不言
不言nach vorne
2018-09-28 17:27:033839Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Frage, was der Diff-Algorithmus in React ist. Die Strategie und Implementierung des Diff-Algorithmus haben einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen.

1. Was ist ein Diff-Algorithmus?

  • Traditioneller Diff: Der Diff-Algorithmus ist der Differenzsuchalgorithmus; für die HTML-DOM-Struktur ist er der Unterschied Suche nach Baumalgorithmus; die zeitliche Komplexität der Berechnung der Differenz zwischen zwei Bäumen ist offensichtlich zu teuer und es ist für React unmöglich, diesen traditionellen Algorithmus zu übernehmen; 🎜>

    React Diff:
  • Wie bereits erwähnt, nutzt React die virtuelle DOM-Technologie, um das reale DOM abzubilden, also die Differenzsuche von React Der Diff-Algorithmus dient im Wesentlichen dem Vergleich zweier JavaScript-Objektunterschiede.
    • basiert auf drei Strategien:

    • Cross- Ebenenbewegungsoperation von DOM-Knoten in der Web-Benutzeroberfläche Sehr klein und kann ignoriert werden. (Baumunterschied)
  1. Zwei Komponenten mit derselben Klasse erzeugen ähnliche Baumstrukturen, und zwei Komponenten mit unterschiedlichen Klassen erzeugen unterschiedliche Baumstrukturen (Komponentenunterschied)

  2. Eine Gruppe untergeordneter Knoten auf derselben Ebene kann durch eine eindeutige ID unterschieden werden. (Element Diff)

  3. 2. Interpretation des React Diff-Algorithmus

Zunächst muss klar sein, dass Diff dies tut treten nur während der React-Update-Phase auf. Anwendung des Algorithmus

  • React-Update-Mechanismus:

Was ist der Diff-Algorithmus in React? Strategie und Implementierung des Diff-AlgorithmusStrategiediagramm zur Optimierung des React Diff-Algorithmus:

Was ist der Diff-Algorithmus in React? Strategie und Implementierung des Diff-AlgorithmusReact Die Aktualisierungsphase bestimmt den ReactElement-Typ und führt verschiedene Vorgänge aus. Zu den ReactElement-Typen gehören drei Typen: Text, Dom und Komponenten.

  • Die Aktualisierungsverarbeitungsmethode von Jeder Elementtyp:

  • Die Aktualisierung benutzerdefinierter Elemente dient hauptsächlich der Aktualisierung der gerenderten Knoten, und der Ladenbesitzer überlässt es der entsprechenden Komponente der gerenderten Knoten, die Aktualisierungen zu verwalten .
    • Das Aktualisieren des Textknotens ist sehr einfach. Aktualisieren Sie einfach die Kopie direkt.

    • Die Aktualisierung der Grundelemente des Browsers gliedert sich in zwei Teile:

    • Attribute aktualisieren, vergleichen Sie das Vorherige und nach den Attributen unterschiedlich, teilweise Aktualisierung. Und behandeln Sie spezielle Eigenschaften, wie z. B. die Ereignisbindung.
  1. Die Aktualisierung von untergeordneten Knoten dient hauptsächlich dazu, die Differenzobjekte zu finden. Beim Auffinden der Differenzobjekte verwenden wir auch die obige „shouldUpdateReact“-Komponente, um zu beurteilen, ob sie direkt aktualisiert werden kann Rufen Sie die Aktualisierung des untergeordneten Knotens auf, wodurch das Differenzobjekt ebenfalls rekursiv gefunden wird. Das Löschen früherer Objekte oder das Hinzufügen neuer Objekte kann nicht direkt aktualisiert werden. Betreiben Sie dann das DOM-Element (Position ändern, löschen, hinzufügen usw.) entsprechend dem Differenzobjekt.

Tatsächlich wird der Diff-Algorithmus nur während des DOM-Elementaktualisierungsprozesses in der React-Aktualisierungsphase aufgerufen. Warum sagen Sie das? ?
  • 1. Wenn der Texttyp aktualisiert wird
  • und der Inhalt unterschiedlich ist, wird er direkt aktualisiert und ersetzt, ohne den komplexen Diff-Algorithmus aufzurufen:
 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. Für benutzerdefinierte Komponentenelemente:

class Tab extends Component {
    constructor(props) {
        super(props);
        this.state = {
            index: 1,
        }
    }
    shouldComponentUpdate() {
        ....
    }
    render() {
        return (
            <p>
                </p><p>item1</p>
                <p>item1</p>
            
        )
    }
    
}

Was eine Komponente ist, kann man sagen ist nur ein Verpackungscontainer einer HTML-Struktur und hat die Fähigkeit, den Status dieser HTML-Struktur zu verwalten.

  • Zum Beispiel ist die oben erwähnte Tab-Komponente: ihr wesentlicher Inhalt Die von der Renderfunktion zurückgegebene HTML-Struktur und die sogenannte Tab-Klasse sind der Verpackungscontainer dieser HTML-Struktur (kann als Verpackungsbox verstanden werden).

  • Wie Sie sehen können Im Diagramm des React-Rendering-Mechanismus wird die benutzerdefinierte Komponente schließlich mit der React Diff-Optimierungsstrategie 1 kombiniert (Zwei Komponenten verschiedener Klassen haben unterschiedliche Strukturen)

  • 3 🎜>
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
    );

    // ......
}

Dabei wird der Diff-Algorithmus intern in der _updateDOMChildren-Methode aufgerufen.

  • 3. Implementierung des Diff-Algorithmus in React

    _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])
            );
          }
        }
      }
    Entwicklungsvorschläge basierend auf Diff

Wann Entwickeln Sie Komponenten basierend auf Baumunterschieden:

  • , achten Sie darauf, die DOM-Struktur stabil zu halten, dh die DOM-Struktur so wenig wie möglich dynamisch zu manipulieren, insbesondere mobil Operationen.

  1. Wenn die Anzahl der Knoten zu groß ist oder die Seite zu oft aktualisiert wird, wird die Seitenverzögerung deutlicher.

  2. Zu diesem Zeitpunkt können Sie Knoten über CSS ausblenden oder anzeigen, anstatt DOM-Knoten tatsächlich zu entfernen oder hinzuzufügen.

  3. Basierend auf Komponentenunterschied
  4. :
  1. Achten Sie auf die Verwendung von ShouldComponentUpdate(), um unnötige Aktualisierungen von Komponenten zu reduzieren.

  2. Ähnliche Strukturen sollten so weit wie möglich in Komponenten gekapselt werden, was nicht nur die Codemenge reduziert, sondern auch den Leistungsverbrauch von Komponentenunterschieden verringert.

  • Basierend auf Elementdiff:

    1. Versuchen Sie bei Listenstrukturen, so etwas wie zu minimieren Das Hinzufügen des letzten Knotens an den Kopf der Liste wirkt sich in gewissem Maße auf die Renderleistung von React aus, wenn die Anzahl der Knoten zu groß ist oder die Aktualisierungsvorgänge zu häufig sind.

    Das obige ist der detaillierte Inhalt vonWas ist der Diff-Algorithmus in React? Strategie und Implementierung des Diff-Algorithmus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen