Maison  >  Article  >  interface Web  >  Une brève analyse du mécanisme de détection des changements d'Angular et comment optimiser les performances ?

Une brève analyse du mécanisme de détection des changements d'Angular et comment optimiser les performances ?

青灯夜游
青灯夜游avant
2022-05-11 10:35:362592parcourir

Qu'est-ce que la détection des changements ? L'article suivant vous amènera à comprendre le mécanisme de détection des changements dans Angular, à expliquer le fonctionnement de la détection des changements et à présenter la méthode d'optimisation des performances de la détection des changements angulaires. J'espère que cela sera utile à tout le monde !

Une brève analyse du mécanisme de détection des changements d'Angular et comment optimiser les performances ?

Qu'est-ce que la détection de changement ?

Le concept de détection des changements

Une fois l'état des données dans le composant modifié, la vue doit être mise à jour en conséquence. Ce mécanisme de synchronisation des vues et des données est appelé détection des modifications. [Recommandation du didacticiel connexe : "Tutoriel angulaire"]

Moment de déclenchement de la détection des changements

Tant qu'une opération asynchrone (Événements, Minuterie, XHR) se produit, Angular pensera que l'état a peut-être changé, puis il effectuera une détection de changement.

  • Événements : : clic, survol, mouseout, keyup, keydown et autres événements du navigateur ;
  • Timer : setTimeout/setInterval ;
  • XHR : Diverses demandes, etc.

Puisque la détection des changements est effectuée sur des opérations asynchrones, comment Angular s'abonne-t-il aux requêtes asynchrones et effectue-t-il la détection des changements ?

Nous présentons ici NgZone et son objet fork Zone.js. NgZone以及它的fork对象Zone.js

Zone.js 用于封装和拦截浏览器中的异步活动、它还提供 异步生命周期的钩子 和 统一的异步错误处理机制。

Zone.js 是通过 Monkey Patching(猴子补丁) 的方式来对浏览器中的常见方法和元素进行拦截,例如 setTimeout 和 HTMLElement.prototype.onclick。Angular 在启动时会利用 Zone.js 修补几个低级浏览器 API,从而实现异步事件的捕获,并在捕获时间后调用变更检测。

Angular通过forkZone.js并拓展出一个自己的区域NgZone,让应用中的所有异步操作都会运行在这个区域中。

Angular的变更检测如何工作的?

Angualr会为每一个组件生成一个变化监测器changeDetector ,记录组件的变化状态。

我们在创建了一个Angular 应用后,Angular 会同时创建一个 ApplicationRef  的实例,这个实例代表的就是我们当前创建的这个 Angular 应用的实例。 ApplicationRef 创建的同时,会订阅 ngZone 中的 onMicrotaskEmpty  事件,在所有的微任务完成后调用所有的视图的detectChanges()来执行变更检测。

变更检测的执行顺序

  • 更新所有子子组件绑定的属性

  • 调用所有子组件生命周期的钩子 OnChanges, OnInit, DoCheck,AfterContentInit

  • 更新当前组件的DOM

  • 调用子组件的变更检测

  • 调用所有子组件的生命周期钩子 ngAfterViewInit

举个栗子,我们在开发模式的时候可能会遇到这种报错:

Une brève analyse du mécanisme de détection des changements dAngular et comment optimiser les performances ?

这是由于变更检测遵循从根组件开始,从上到下,执行每个组件的变更检测,直到最后一个组件达到稳定状态。而在下一次变更检测之前,子孙组件都不允许去修改父组件里的属性。

情况1 在开发模式下,Angular会进行二次检测 (生产环境下调用enableProdMode()Zone.js est utilisé pour encapsuler et intercepter les activités asynchrones dans le navigateur. Il fournit également des hooks de cycle de vie asynchrone

et un

mécanisme de gestion des erreurs asynchrones unifié. Zone.js utilise Monkey Patching

pour intercepter les méthodes et éléments courants dans les navigateurs, tels que setTimeout et HTMLElement.prototype.onclick . Angular exploite Zone.js pour corriger plusieurs API de navigateur de bas niveau au démarrage afin de capturer les événements asynchrones et d'appeler la détection des modifications après le temps de capture.

Angular forke Zone.js et étend sa propre zone NgZone, de sorte que toutes les opérations asynchrones de l'application s'exécuteront dans cette zone.

Comment fonctionne la détection des changements d'Angular ?
  • Angualr générera un détecteur de changement changeDetector pour chaque composant afin d'enregistrer l'état de changement du composant. Après avoir créé une application Angular, Angular créera également une instance de ApplicationRef. Cette instance représente l'instance de l'application Angular que nous créons actuellement. Lorsque ApplicationRef est créé, il s'abonnera à onMicrotaskEmpty, une fois toutes les microtâches terminées, appelez detectChanges() de toutes les vues pour effectuer la détection des modifications.

    Ordre d'exécution de la détection des modifications

      🎜🎜Mettre à jour les propriétés liées à tous les sous-composants enfants🎜🎜 🎜 🎜Appelez les hooks de cycle de vie OnChanges, OnInit, DoCheck, AfterContentInit de tous les sous-composants🎜🎜🎜🎜Mettre à jour le DOM du composant actuel🎜🎜🎜🎜Appelez la détection de changement du sous-composant🎜🎜🎜🎜Appelez le hook de cycle de vie ngAfterViewInit de tous les sous-composants🎜🎜 🎜🎜Par exemple, nous pouvons rencontrer cette erreur lorsque nous sommes en mode développement : 🎜🎜Une brève analyse du mécanisme de détection des changements dAngular et comment optimiser les performances ?🎜🎜Cela est dû au fait que la détection des changements suit en commençant par le composant racine, de haut en bas, en effectuant une détection des changements pour chaque composant jusqu'à ce que le dernier composant atteigne un état stable. Avant la prochaine détection de changement, les composants descendants ne sont pas autorisés à modifier les propriétés du composant parent. 🎜🎜🎜🎜Cas 1🎜🎜 En mode développement, Angular effectuera une 🎜détection secondaire🎜 (lors de l'appel de enableProdMode() dans l'environnement de production, le nombre de détections sera réduit à 1). Une fois que nous modifions les propriétés du composant parent dans le composant descendant après avoir terminé l'🎜Étape 4🎜, lorsque Angular effectue la deuxième détection et constate que les deux valeurs sont incohérentes, l'erreur ci-dessus se produira. 🎜🎜🎜🎜Cas 2🎜🎜 Tant que le composant parent lie les propriétés au composant enfant, que le code suivant soit exécuté ou non dans l'un des hooks de cycle de vie parmi OnChanges, OnInit, DoCheck, AfterContentInit et AfterViewInit, une erreur sera être signalé. 🎜
      // #parent
      {{data}}
      <child [data]="data"></child>
      
      // in child component ts, execute:
      this.parent.data = &#39;new Value&#39;;
      🎜🎜Stratégie d'exécution pour la détection des changements🎜🎜🎜🎜🎜🎜🎜🎜Stratégie par défaut🎜🎜🎜🎜

      Chaque fois qu'un événement déclenche une détection de changement (tels que des événements utilisateur, des minuteries, XHR, des promesses, etc.), cette stratégie par défaut vérifie chaque composant de l'arborescence des composants de haut en bas. Cette méthode de vérification conservatrice qui ne fait aucune hypothèse sur les dépendances des composants est appelée vérification sale. Cette stratégie aura un impact sur les performances de notre application lorsque nous appliquons trop de composants.

  • Stratégie OnPush

    Modifiez le changeDetection du décorateur de composant Après l'avoir défini sur la stratégie OnPush, Angular ignorera le composant et le composant à chaque changement. la détection est déclenchée. Détection des modifications de tous les sous-composants du composant. changeDetection,设置为 OnPush 策略后,Angular 每次触发变化检测后会跳过该组件和该组件的所以子组件变化检测。

    在 OnPush 策略下,只有以下这几种情况才会触发组件的变化检测:

    • 输入值(@Input)更改(入input的值必须是一个新的引用)
    • 当前组件或子组件之一触发了事件 (但在onPush策略中,以下操作不会触发变更检测)
      • setTimeout()
      • setInterval()
      • Promise.resolve().then()
      • this.http.get('...').subscribe()
    • 手动触发变更检测(每个组件都会关联一个组件视图ChangeDetectorRef)
      • detectChanges(): 它会触发当前组件和子组件的变化检测
      • markForCheck(): 它不会触发变化检测,但是会把当前的OnPush组件和所以的父组件为OnPush的组件 标记为需要检测状态 ,在当前或者下一个变化检测周期进行检测
      • ApplicationRef.tick() : 它会根据组件的变化检测策略,触发整个应用程序的更改检测
      Une brève analyse du mécanisme de détection des changements dAngular et comment optimiser les performances ?
    • async pipe

对于Angular的变更检测如何优化?

由于组件默认执行 Default策略 ,任何异步操作都会触发整个组件数从上到下的检查。即使Angular团队不断提升性能,可以在毫秒内完成上百次检测,但是当应用拓展至百上千个组件组成时,庞大的组件树对应的变更检测也会达到性能瓶颈。

此时,我们就需要开始分析并减少不必要的检测次数。

如何减少检测次数

  • 区域污染(Zone Pollution)

    一般我们在生命周期钩子里使用第三方库,比如chart类库初始化,会自带requestAnimationRequest/setTimeout/addEventListener,我们可以将初始化方法写入NgZonerunOutsideAngular方法中。

Une brève analyse du mécanisme de détection des changements dAngular et comment optimiser les performances ?

  • OnPush 策略

    对于不涉及更新操作的视图可以剥离出组件,使用onPush策略,以通知更新的方式刷新视图(见上方 变更检测的执行策略 部分)。

Une brève analyse du mécanisme de détection des changements dAngular et comment optimiser les performances ?

  • pure pipe 代替 {{function(data)}}

    在html文件内,{{function(data)}}

    Sous la stratégie OnPush, seules les situations suivantes déclencheront la détection de changement de composant :

    • La valeur d'entrée (@Input) change
    (la valeur saisie en entrée doit être une nouvelle référence)

    Une brève analyse du mécanisme de détection des changements dAngular et comment optimiser les performances ?

    L'un des composants ou sous-composants actuels a déclenché l'événement

    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