Maison  >  Article  >  interface Web  >  Qu'est-ce que l'algorithme Diff dans React ? Stratégie et implémentation de l'algorithme Diff

Qu'est-ce que l'algorithme Diff dans React ? Stratégie et implémentation de l'algorithme Diff

不言
不言avant
2018-09-28 17:27:033836parcourir

Le contenu de cet article porte sur ce qu'est l'algorithme Diff dans React ? La stratégie et la mise en œuvre de l'algorithme Diff ont une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer, j'espère que cela vous sera utile.

1. Qu'est-ce que l'algorithme Diff

  • Diff traditionnel : l'algorithme diff est l'algorithme de recherche de différence pour la structure HTML DOM, c'est la différence ; Algorithme de recherche d'arbre ; la complexité temporelle du calcul de la différence entre deux arbres est O(n^3), ce qui est évidemment trop coûteux et il est impossible pour React d'adopter cet algorithme traditionnel ; 🎜>

    React Diff :
  • Comme mentionné précédemment, React utilise la technologie DOM virtuel pour cartographier le DOM réel, c'est-à-dire la recherche de différence du React L'algorithme Diff consiste essentiellement à comparer deux JavaScripts. La recherche de différence d'objets
    • est basée sur trois stratégies :

    • Cross- opération de mouvement de niveau des nœuds DOM dans l'interface utilisateur Web Très petite et peut être ignorée. (diff d'arbre)
  1. Deux composants avec la même classe généreront des structures arborescentes similaires, et deux composants avec des classes différentes généreront des structures arborescentes différentes (diff de composant)

  2. Pour un groupe de nœuds enfants de même niveau, ils peuvent être distingués par un identifiant unique. (élément diff)

  3. 2. Interprétation de l'algorithme React Diff

Tout d'abord, il doit être clair que Diff sera ne se produisent que pendant la phase de mise à jour de React Application de l'algorithme

  • Mécanisme de mise à jour de React :

Quest-ce que lalgorithme Diff dans React ? Stratégie et implémentation de lalgorithme DiffTableau de stratégie d'optimisation de l'algorithme React Diff :

Quest-ce que lalgorithme Diff dans React ? Stratégie et implémentation de lalgorithme DiffReact La phase de mise à jour déterminera le type ReactElement et effectuera différentes opérations ; les types ReactElement incluent trois types : texte, Dom et composants

  • La méthode de traitement de mise à jour de ; chaque type d'élément :

  • La mise à jour des éléments personnalisés consiste principalement à mettre à jour les nœuds rendus, et le commerçant laisse au composant correspondant des nœuds rendus le soin de gérer les mises à jour .
    • La mise à jour du nœud de texte est très simple, il suffit de mettre à jour la copie directement.

    • La mise à jour des éléments de base du navigateur est divisée en deux parties :

    • Mettre à jour les attributs, comparer l'avant et après les attributs Mise à jour différente et partielle. Et gérez les propriétés spéciales, telles que la liaison d’événements.
  1. La mise à jour des nœuds enfants. La mise à jour des nœuds enfants consiste principalement à trouver les objets de différence, nous utiliserons également le ShouldUpdateReactComponent ci-dessus pour juger s'il peut être mis à jour directement. , ce sera récursif Appelez la mise à jour du nœud enfant, qui trouvera également l'objet différence de manière récursive. La suppression d'objets précédents ou l'ajout de nouveaux objets ne peuvent pas être directement mis à jour. Opérez ensuite l'élément DOM (changement de position, suppression, ajout, etc.) en fonction de l'objet de différence.

En fait, l'algorithme Diff n'est appelé que pendant le processus de mise à jour des éléments DOM dans la phase de mise à jour de React Pourquoi dites-vous cela ; ?
  • 1. Si le type de texte est mis à jour
  • et que le contenu est différent, il sera directement mis à jour et remplacé, et l'algorithme complexe Diff ne le sera pas. être appelé :

2. Pour les éléments de composant personnalisés :

 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
        );
      }
    }
  }

Ce qu'il faut clarifier, c'est ce qu'est un composant. .On peut dire qu'un composant n'est qu'un morceau de Html Le conteneur d'emballage de la structure, et a la capacité de gérer le statut de cette structure Html
class Tab extends Component {
    constructor(props) {
        super(props);
        this.state = {
            index: 1,
        }
    }
    shouldComponentUpdate() {
        ....
    }
    render() {
        return (
            <p>
                </p><p>item1</p>
                <p>item1</p>
            
        )
    }
    
}
  • Par exemple, le ci-dessus Composant Tab : son contenu essentiel est la structure Html renvoyée par la fonction de rendu, et ce que nous appelons la classe Tab est le conteneur d'emballage de cette structure Html (peut être compris comme une boîte d'emballage

  • Comme vous pouvez le voir dans le diagramme du mécanisme de rendu React, le composant personnalisé est finalement combiné avec la première stratégie d'optimisation React Diff (deux composants de catégories différentes ont des structures différentes)

  • 3. Éléments de base :

L'algorithme diff est appelé dans la méthode this._updateDOMChildren.

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
    );

    // ......
}
  • 3. Implémentation de l'algorithme Diff dans React

  • 4 Suggestions de développement basées sur Diff

_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])
        );
      }
    }
  }
Basé sur les différences d'arbre :

  • Lors du développement de composants, faites attention à maintenir la structure DOM stable, c'est-à-dire à exploiter dynamiquement la structure DOM le moins possible, en particulier les opérations mobiles.

    Lorsque le nombre de nœuds est trop grand ou que la page est mise à jour trop de fois, le décalage de la page sera plus évident.
  1. À l'heure actuelle, vous pouvez masquer ou afficher les nœuds via CSS au lieu de supprimer ou d'ajouter des nœuds DOM.
  2. Basé sur la différence des composants

     :
    1. Faites attention à utiliser ShouldComponentUpdate() pour réduire les mises à jour inutiles des composants.

    2. Les structures similaires doivent être encapsulées dans des composants autant que possible, ce qui réduit non seulement la quantité de code, mais réduit également la consommation de performances des différences de composants.

  3. Basé sur la différence d'élément :

    1. Pour les structures de liste, essayez de minimiser quelque chose comme l'ajout du dernier L'opération de déplacement des nœuds en tête de liste affectera dans une certaine mesure les performances de rendu de React lorsque le nombre de nœuds est trop grand ou que les opérations de mise à jour sont trop fréquentes.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer