Maison > interface Web > js tutoriel > Une brève analyse du mécanisme de mise à jour du DOM dans la détection des changements angulaires

Une brève analyse du mécanisme de mise à jour du DOM dans la détection des changements angulaires

青灯夜游
Libérer: 2022-12-12 20:21:15
avant
2565 Les gens l'ont consulté

Une brève analyse du mécanisme de mise à jour du DOM dans la détection des changements angulaires

La détection des changements est une partie importante de Angular, qui consiste à maintenir la synchronisation entre le modèle et la vue. Dans le processus de développement quotidien, nous n'avons pas besoin de connaître la détection des changements, car Angular nous aide à terminer cette partie du travail, permettant aux développeurs de se concentrer davantage sur la mise en œuvre commerciale, améliorant ainsi l'efficacité du développement et l'expérience de développement. Mais si vous souhaitez utiliser le framework en profondeur, ou si vous souhaitez écrire du code hautes performances au lieu de simplement implémenter des fonctions, vous devez comprendre la détection des changements. Cela peut nous aider à mieux comprendre le framework, à déboguer les erreurs, à améliorer les performances, etc. [Recommandation de didacticiel connexe : "Tutoriel angulaire"]

Mécanisme de mise à jour du DOM d'Angular

Regardons d'abord un petit exemple.

Lorsque nous cliquons sur le bouton, l'attribut de nom est modifié et le DOM est automatiquement mis à jour avec la nouvelle valeur de nom.

Maintenant, il y a une question. Si je change la valeur de name puis que je produis le innerText dans le DOM, quelle sera cette valeur ?

import { Component, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Empty';

  @ViewChild('textContainer') textContainer: ElementRef;

  normalClick(): void {
    this.name = 'Hello Angular';

    console.log(this.textContainer.nativeElement.innerText);
  }
}
Copier après la connexion

Avez-vous répondu correctement ?

Alors, que se passe-t-il exactement dans ces deux morceaux de code ?

Si nous utilisons JS natif pour écrire ce code, alors la vue ne changera certainement pas après avoir cliqué sur le bouton, mais la vue change dans Angular, alors pourquoi met-elle automatiquement à jour la vue ? Ceci est indissociable d'une bibliothèque appelée zone.js. Pour faire simple, il effectue un traitement des événements où les valeurs changent. Cela sera expliqué en détail dans les sections suivantes. Il suffit de le savoir pour l'instant.

Si je ne veux pas que cette bibliothèque effectue ce traitement, Angular nous fournit également un moyen de désactiver zone.js.

Vous pouvez désactiver zone.js dans main.ts.

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule, {
  ngZone: 'noop'
})
  .catch(err => console.error(err));
Copier après la connexion

Lorsque nous désactivons zone.js, la vue n'est pas mise à jour. Accédez au code source pour trouver le code pertinent pour la mise à jour de la vue.

 */
class ApplicationRef {
    /** @internal */
    constructor(_zone, _injector, _exceptionHandler, _initStatus) {
        this._zone = _zone;
        this._injector = _injector;
        this._exceptionHandler = _exceptionHandler;
        this._initStatus = _initStatus;
        /** @internal */
        this._bootstrapListeners = [];
        this._views = [];
        this._runningTick = false;
        this._stable = true;
        this._destroyed = false;
        this._destroyListeners = [];
        /**
         * Get a list of component types registered to this application.
         * This list is populated even before the component is created.
         */
        this.componentTypes = [];
        /**
         * Get a list of components registered to this application.
         */
        this.components = [];
        this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({
            next: () => {
                this._zone.run(() => {
                    this.tick();
                });
            }
        });
        ...
    }

/**
     * Invoke this method to explicitly process change detection and its side-effects.
     *
     * In development mode, `tick()` also performs a second change detection cycle to ensure that no
     * further changes are detected. If additional changes are picked up during this second cycle,
     * bindings in the app have side-effects that cannot be resolved in a single change detection
     * pass.
     * In this case, Angular throws an error, since an Angular application can only have one change
     * detection pass during which all change detection must complete.
     */
    tick() {
        NG_DEV_MODE && this.warnIfDestroyed();
        if (this._runningTick) {
            const errorMessage = (typeof ngDevMode === 'undefined' || ngDevMode) ?
                'ApplicationRef.tick is called recursively' :
                '';
            throw new RuntimeError(101 /* RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK */, errorMessage);
        }
        try {
            this._runningTick = true;
            for (let view of this._views) {
                view.detectChanges();
            }
            if (typeof ngDevMode === 'undefined' || ngDevMode) {
                for (let view of this._views) {
                    view.checkNoChanges();
                }
            }
        }
        catch (e) {
            // Attention: Don't rethrow as it could cancel subscriptions to Observables!
            this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
        }
        finally {
            this._runningTick = false;
        }
    }

}
Copier après la connexion

Interprétation large, ce ApplicationRef est une instance de l'application Angular entière. Dans le constructeur, onMicrotaskEmpty de zone (bibliothèque de zones) (d'après le nom, c'est un sujet qui efface les micro-tâches). souscrit une fois. Dans l'abonnement, tick() est appelé, alors que fait-on dans le tick ?

Réflexion :

J'ai dit la dernière fois qu'il valait mieux ne pas s'abonner au constructeur. Pourquoi est-ce si irrégulier ici ? Bien sûr que non. La dernière fois, nous avons parlé des composants angulaires qui doivent être placés dans

constructor

et de ceux qui doivent être placés dans ngOnInit. Mais ici, ApplicationRef est un service, donc le code d'initialisation ne peut être placé que dans constructor. Dans la fonction tick, s'il s'avère que la fonction tick est en cours d'exécution, une exception sera levée car il s'agit d'une instance de l'application entière et ne peut pas être appelée de manière récursive. Ensuite, toutes les vues sont parcourues, puis chaque vue exécute

detectChanges

(), ce qui signifie que la détection des changements est exécutée. Qu'est-ce que la détection des changements sera expliqué en détail plus tard. Ensuite, s'il s'agit de devMode, parcourez à nouveau toutes les vues et chaque vue exécute checkNoChanges() pour vérifier s'il y a des changements. S'il y a des changements, une erreur sera générée (Je parlerai de ce problème en détail plus tard. , sautez-le pour l'instant) . D'accord, maintenant je sais comment le mettre à jour, c'est-à-dire appeler la méthode

tick

de ApplicationRef.

import { Component, ViewChild, ElementRef, ApplicationRef } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent  {
  name = 'Empty';

  @ViewChild('textContainer') textContainer: ElementRef = {} as any;

  constructor(private app: ApplicationRef){}

  normalClick(): void {
    this.name = 'Hello Angular';

    console.log(this.textContainer.nativeElement.innerText);

    this.app.tick();
  }
}
Copier après la connexion
Effectivement, la vue peut être mise à jour normalement.

Revoyons-le brièvement. La mise à jour du DOM repose sur le déclenchement de

tick()

zone.js aide les développeurs à éviter de déclencher cette opération manuellement. D'accord, vous pouvez maintenant activer zone.js. Alors, qu’est-ce que la détection de changement ? Continuez à attendre avec impatience le prochain article.

Pour plus de connaissances liées à la programmation, veuillez visiter :

Enseignement de la programmation

 ! !

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!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal