Maison  >  Article  >  interface Web  >  De quels algorithmes le framework React dispose-t-il ? Explication détaillée de l'algorithme du framework React

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de l'algorithme du framework React

寻∝梦
寻∝梦original
2018-09-11 14:58:161703parcourir

Cet article donne principalement une explication détaillée des principes du framework react. Il y a également beaucoup de compréhension approfondie de React ci-dessous. Jetons un coup d'œil à cet article maintenant

.

Je travaille sur React depuis plus de 2 ans. J'aime et déteste ce framework. Tout le monde connaît ses avantages, mais ses défauts sont progressivement révélés. grand projet , lorsqu'il est combiné avec des frameworks tiers tels que Redux et ReactRouter, la quantité de code métier complexe deviendra très importante (le code frontal est souvent 1,5 fois la taille précédente). Si la conception sous-jacente n'est pas bonne au début, vous serez souvent confronté au problème d'une faible efficacité de développement. Ce qui suit résume quelques concepts fondamentaux du framework React, j'espère qu'il sera utile à tout le monde :

L'algorithme diff de React

L'algorithme diff de React est Virtual DOM La raison pour laquelle la volonté est la plus grande confiance est que nous savons tous que les performances d'une page sont généralement déterminées par la vitesse de rendu et le nombre de rendus. Comment maximiser l'utilisation de l'algorithme diff pour le développement ? Voyons d'abord comment cela fonctionne.

Algorithme de comparaison traditionnel

Calculez les opérations minimales requises pour convertir une structure arborescente en une autre structure arborescente. L'algorithme de comparaison traditionnel compare les nœuds de manière séquentielle via la récursion de boucle, ce qui est inefficace et complexe. O(n^3), où n est le nombre total de nœuds dans l'arborescence. Autrement dit, si vous souhaitez afficher 1 000 nœuds, vous devrez effectuer des milliards de comparaisons en séquence. Cette consommation de performances est inacceptable pour les projets front-end.

Algorithme de base

Comme vu ci-dessus, la complexité de l'algorithme de comparaison traditionnel est O(n^3), qui ne peut évidemment pas répondre aux exigences de performances. Et React transforme les problèmes de O(n^3) complexité en problèmes de O(n) complexité en formulant des stratégies audacieuses. Comment a-t-il fait ?

diff d'arbre

Il existe très peu d'opérations de déplacement inter-niveaux des nœuds DOM dans l'interface utilisateur Web et peuvent être ignorées. React a réalisé une optimisation concise et claire de l'algorithme d'arbre, c'est-à-dire qu'une comparaison hiérarchique d'arbres ne comparera que les nœuds du même niveau. Comme le montre la figure ci-dessous :

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

React utilise updateDepth pour contrôler le niveau de l'arborescence DOM virtuelle. Seuls les nœuds DOM dans la même zone de couleur seront comparés. c'est-à-dire que la même couleur sera comparée. Tous les nœuds enfants sous un nœud parent. Lorsqu'il s'avère qu'un nœud n'existe plus, le nœud et ses sous-nœuds seront complètement supprimés et ne seront plus utilisés pour d'autres comparaisons. De cette façon, un seul parcours de l’arborescence est nécessaire pour terminer la comparaison de l’ensemble de l’arborescence DOM.

// tree diff算法实现updateChildren: function(nextNestedChildrenElements, transaction, context) {
  updateDepth++;  var errorThrown = true;  try {    this._updateChildren(nextNestedChildrenElements, transaction, context);
    errorThrown = false;
  } finally {
    updateDepth--;    if (!updateDepth) {      if (errorThrown) {
        clearQueue();
      } else {
        processQueue();
      }
    }
  }
}

Pourquoi devrions-nous réduire les opérations inter-niveaux des nœuds DOM ?

Comme indiqué ci-dessous, le nœud A (y compris ses sous-nœuds) est entièrement déplacé vers le nœud D puisque React ne considérera que simplement la transformation de position des nœuds de même niveau, et pour les nœuds de niveaux différents. , il ne fait que les créer et les supprimer. Lorsque le nœud racine découvre que A a disparu dans le nœud enfant, il détruira directement A ; lorsque D découvre qu'il y a un nœud enfant supplémentaire A, il créera un nouveau A (y compris les nœuds enfants) comme nœud enfant. À l'heure actuelle, l'état d'exécution de React diff est : créer A -> créer B -> créer C -> supprimer A.

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

On peut constater que lorsqu'un nœud se déplace à travers les niveaux, l'opération de mouvement imaginaire ne se produira pas, mais l'arbre avec A comme nœud racine sera complètement recréé. , une opération qui affecte les React performances.

component diff

Deux composants avec la même classe généreront des arborescences similaires, et deux composants avec des classes différentes généreront des arborescences différentes.

  • S'il s'agit de composants du même type, continuez à comparer selon la stratégie d'origine virtual DOM tree.

  • Sinon, le composant sera jugé comme dirty component, remplaçant ainsi tous les nœuds enfants sous l'ensemble du composant.

  • Pour le même type de composant, il est possible que son Virtual DOM ne présente aucun changement. Si vous pouvez en être sûr, vous pouvez gagner beaucoup de temps de fonctionnement des différences, donc. React permet aux utilisateurs d'utiliser shouldComponentUpdate() pour déterminer si le composant doit être comparé.

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

Comme indiqué ci-dessus, lorsque component D est remplacé par component G, même si les deux component ont des structures similaires, une fois que React détermine que D et G sont des types de composants différents, les structures des deux seront ne pas être comparé. Au lieu de cela, supprimez component D directement et recréez component G et ses nœuds enfants. Bien que lorsque deux component sont de types différents mais ont des structures similaires, React diff affectera les performances, mais comme le dit le blog officiel React : Différents types de component ont peu de chances d'être similaires DOM tree, c'est donc Il est difficile pour des facteurs aussi extrêmes d’avoir un impact significatif sur le processus de développement.

element diff

Pour un groupe de nœuds enfants de même niveau, ils peuvent être distingués par un identifiant unique. React propose une stratégie d'optimisation : les développeurs sont autorisés à ajouter des clés uniques pour distinguer le même groupe de nœuds enfants au même niveau. Bien qu'il ne s'agisse que d'un petit changement, les performances ont subi des changements bouleversants !

Les nœuds contenus dans les nouvelles et anciennes collections sont comme indiqué dans la figure ci-dessous. Les nouvelles et anciennes collections sont comparées par diff. Grâce à la clé, on constate que les nœuds des nouvelles et anciennes collections sont. les mêmes nœuds, il n'est donc pas nécessaire de supprimer et de créer des nœuds, il vous suffit de déplacer les positions des nœuds dans l'ancien ensemble et de les mettre à jour avec les positions des nœuds dans le nouvel ensemble. Le résultat donné par React est le suivant : B et D n'effectuent aucune opération et A et C effectuent des opérations de déplacement.

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

Suggestions de développement

(1)[basées sur les différences d'arborescence] Lors du développement de composants, le maintien d'une structure DOM stable permet de maintenir l'ensemble performance. En d’autres termes, effectuez le moins de manipulations dynamiques possible de la structure du DOM, en particulier les opérations de mouvement. Lorsque le nombre de nœuds est trop grand ou que la page est mise à jour trop souvent, le phénomène de gel de la page est plus évident. Vous pouvez masquer ou afficher des nœuds via CSS sans supprimer ni ajouter de nœuds DOM.

(2)[Basé sur les différences entre les composants] Lors du développement de composants, faites attention à utiliser shouldComponentUpdate() pour réduire les mises à jour inutiles des composants. De plus, des structures similaires doivent être regroupées autant que possible en composants, ce qui réduit non seulement la quantité de code, mais réduit également la component diff consommation de performances.

(3)[Basé sur la différence d'élément] Pour les structures de liste, essayez de réduire les opérations comme déplacer le dernier nœud en tête de la liste lorsque le nombre de nœuds est trop grand ou. les opérations de mise à jour sont trop fréquentes, cela affectera dans une certaine mesure les performances de rendu de React.

Cycle de vie de React

Le cycle de vie de React peut être divisé en quatre situations :

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

  • Lorsqu'il est chargé pour la première fois Lors de l'installation d'un composant, exécutez getDefaultProps, getInitialState, componentWillMount, render et componentDidMount dans l'ordre

  • lors de la désinstallation d'un composant, exécutez ;>componentWillUnmount

  • Lorsque le composant est rechargé,
  • ,

    , getInitialState et componentWillMount sont exécutés dans l'ordre, mais render n'est pas exécuté componentDidMount ; getDefaultProps

  • Lorsque le composant est à nouveau rendu, le composant reçoit l'état mis à jour et exécute
  • ,

    , componentWillReceiveProps, shouldComponentUpdate et componentWillUpdate dans l'ordre. rendercomponentDidUpdate

  • Trois états des composants React

État 1 : MONTAGE

est responsable de la gestion de

, mountComponent dans la vie cycle , getInitialState et componentWillMount. rendercomponentDidMount

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework ReactStatut 2 : RECEIVE_PROPS

est chargé de gérer

, updateComponent, componentWillReceiveProps, shouldComponentUpdate et componentWillUpdate. rendercomponentDidUpdate

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework ReactStatut 3 : DÉMONTAGE

est chargé de gérer

dans le cycle de vie. (Si vous voulez en savoir plus, rendez-vous sur le site Web PHP chinois unmountComponentReact Reference Manual componentWillUnmount pour en savoir plus) Définissez d'abord le statut sur

, si

existe, exécutez ; si à ce moment l'appel UNMOUNTING dans componentWillUnmount ne déclenchera pas componentWillUnmount. L'état de la mise à jour est setState et l'opération de désinstallation du composant est terminée. Le code d'implémentation est le suivant : reRender

// 卸载组件unmountComponent: function() {
  // 设置状态为 UNMOUNTING
  this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;  // 如果存在 componentWillUnmount,则触发
  if (this.componentWillUnmount) {    this.componentWillUnmount();
  }  // 更新状态为 null
  this._compositeLifeCycleState = null;  this._renderedComponent.unmountComponent();  this._renderedComponent = null;

  ReactComponent.Mixin.unmountComponent.call(this);
}

React生命周期总结

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

生命周期 调用次数 能否使用setState()
getDefaultProps 1
getInitialState 1
componentWillMount 1
render >=1
componentDidMount 1
componentWillReceiveProps >=0
shouldComponentUpdate >=0
componentWillUpdate >=0
componentDidUpdate >=0
componentWillUnmount 1
componentDidUnmount 1

setState实现机制

setStateReact框架的核心方法之一,下面介绍一下它的原理:

De quels algorithmes le framework React dispose-t-il ? Explication détaillée de lalgorithme du framework React

// 更新 statesetState: function(partialState, callback) {
  // 合并 _pendingState
  this.replaceState(
    assign({}, this._pendingState || this.state, partialState),
    callback
  );
},

当调用 setState 时,会对 state 以及 _pendingState 更新队列进行合并操作,但其实真正更新 state 的幕后黑手是replaceState

// 更新 statereplaceState: function(completeState, callback) {
  validateLifeCycleOnReplaceState(this);  // 更新队列
  this._pendingState = completeState;  // 判断状态是否为 MOUNTING,如果不是,即可执行更新
  if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
    ReactUpdates.enqueueUpdate(this, callback);
  }
},

replaceState 会先判断当前状态是否为 MOUNTING,如果不是即会调用 ReactUpdates.enqueueUpdate 执行更新。

当状态不为 MOUNTINGRECEIVING_PROPS 时,performUpdateIfNecessary 会获取 _pendingElement_pendingState_pendingForceUpdate,并调用 updateComponent 进行组件更新。

// 如果存在 _pendingElement、_pendingState、_pendingForceUpdate,则更新组件performUpdateIfNecessary: function(transaction) {
  var compositeLifeCycleState = this._compositeLifeCycleState;  // 当状态为 MOUNTING 或 RECEIVING_PROPS时,则不更新
  if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
      compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {    return;
  }  var prevElement = this._currentElement;  var nextElement = prevElement;  if (this._pendingElement != null) {
    nextElement = this._pendingElement;    this._pendingElement = null;
  }  // 调用 updateComponent
  this.updateComponent(
    transaction,
    prevElement,
    nextElement
  );
}

如果在 shouldComponentUpdatecomponentWillUpdate 中调用 setState,此时的状态已经从 RECEIVING_PROPS -> NULL,则 performUpdateIfNecessary 就会调用 updateComponent 进行组件更新,但 updateComponent 又会调用 shouldComponentUpdatecomponentWillUpdate,因此造成循环调用,使得浏览器内存占满后崩溃。

开发建议

不建议在 getDefaultPropsgetInitialStateshouldComponentUpdatecomponentWillUpdaterendercomponentWillUnmount 中调用 setState,特别注意:不能在 shouldComponentUpdatecomponentWillUpdate中调用 setState,会导致循环调用。

本篇文章到这就结束了(想看更多就到PHP中文网React使用手册栏目中学习),有问题的可以在下方留言提问。

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn