<link rel="stylesheet" href="/assets/fonts/jetbrains-mono/jetbrains-mono.css" />
All posts

Signaux angulaires vs Zone.js : Pourquoi Angular devient sans zone

Depuis plus d'une décennie, Angular a résolu un problème fondamental :quand vérifier à nouveau l'interface utilisateur après que quelque chose a changé— avec une solution aussi ingénieuse qu’invasive :Zone.js, une bibliothèque qui réécrit l'API asynchrone du navigateur au moment de l'exécution pour intercepter toute cause possible de changement. Avec l'arrivée deSignaux, Angular abandonne progressivement cette approche au profit d'un modèle dans lequel les données elles-mêmes, et non un patch de singe global, savent qui doit être mis à jour. Cet article explique comment Zone.js fonctionne en interne, pourquoi son modèle présente des limitations structurelles insolubles et ce qu'implique la création d'une application angulaire dans la pratique.sans zone.

Comment fonctionne la détection des modifications basée sur Zone.js

Zone.js résout un problème bien réel : Angular a besoin de savoirQuandrevérifiez les composants pour mettre à jour le DOM, mais JavaScript n'offre pas nativement un moyen de « surveiller » lorsqu'une valeur change de manière générique. La solution de Zone.js est drastique : au démarrage de l'application,écrase(monkey-patch) les API de navigateur asynchrones globales —setTimeout,définirIntervalle,addEventListener,Promesse,XMLHttpRequête- de sorte que chaque fois que l'une de ces API termine une opération, Zone.js l'intercepte et en informe Angular.

Le cycle de détection du changement « généralisé »

Lorsque Zone.js notifie un événement, Angular ne le sait pasquoi exactementil a changé - il le sait justequelque chose, quelque part, cela a peut-être changé. La réponse est de revérifier l'ensemble de l'arborescence des composants de haut en bas (vérification sale), en comparant les valeurs dans les modèles avec celles rendues précédemment :

// Semplificato: cosa succede concettualmente dopo OGNI evento asincrono
zone.onMicrotaskEmpty.subscribe(() => {
  applicationRef.tick(); // ricontrolla l'intero albero dei componenti
});

C'est pourquoi, historiquement, un seulcliquezsur un bouton dans un coin de l'application peut entraîner la revérification de composants totalement indépendants ailleurs dans l'arborescence -ChangeDetectionStrategy.OnPushatténue le problème (ignore les sous-arbres dont@Saisir()ne sont pas modifiés par référence), mais cela ne l'élimine pas : Zone.js continue de déclencher une boucle de contrôle sur chaque événement asynchrone, qu'il conduise ou non à un changement réel.

Les limites structurelles de Zone.js

Zone.js a bien fonctionné en tant que solution « taille unique », mais son approche présente des problèmes qui ne peuvent pas être résolus avec des optimisations incrémentielles :

1. Frais généraux liés au bundle et à l'exécution

Zone.js pèse environ 30 à 35 Ko (minifié) dans le package initial – un coût fixe pour chaque application Angular, quelle que soit la mesure dans laquelle elle utilise réellement ses fonctionnalités. Au moment de l'exécution, le patching de chaque API asynchrone introduit une surcharge mesurable sur chaque appel individuel, même si cela n'entraîne aucun changement réel dans l'interface utilisateur.

2. Détection de changement non sélective

Zone.js saitQuequelque chose s'est passé, mais il ne sait pasQuoi. Le résultat est une boucle de contrôle qui, dans la plupart des cas, revérifie bien plus que nécessaire – même avecSurPushactif partout, chaque événement asynchrone déclenche quand même une ronde de vérification sur l’ensemble de l’arbre potentiellement impliqué.

3. Fragilité avec les bibliothèques tierces

Patching global des API commePromesseoualler chercherpeut interagir de manière imprévisible avec des bibliothèques qui ne s'attendent pas à ce que ces API soient réécrites au moment de l'exécution. Il s'agit d'une cause courante et difficile à diagnostiquer de bogues intermittents dans les grandes applications angulaires.

4. Débogage plus complexe

Les traces de pile traversent le code de correctif de Zone.js, ce qui rend plus difficile la traçabilité de la véritable source d'une erreur asynchrone : toute personne en ayant débogué une.UnhandledPromiseRejectiondans une grande application angulaire connaît ce problème.

Ce que changent les signaux

Signals inverse le modèle : au lieu de "quelque chose s'est passé quelque part, vérifiez tout à nouveau", les données elles-mêmes le saventExactementqui dépend de lui, car la dépendance est explicitement constatée au moment de la lecture :

import { signal, computed, effect } from '@angular/core';

const count = signal(0);
const doubled = computed(() => count() * 2); // dipendenza tracciata automaticamente

effect(() => {
  console.log('Il valore doppio è', doubled());
  // questo effect si ri-esegue SOLO quando doubled() cambia realmente,
  // non ad ogni evento asincrono dell'applicazione
});

count.set(5); // notifica solo i consumer reali: doubled, e l'effect

Quandcompte.set(5)s'appelle, Angular sait précisément lesquelscalculé, lequeleffetet de quelles liaisons de modèles ils dépendentcompter— il n'est pas nécessaire de revérifier l'ensemble de l'arborescence des composants, car le graphe de dépendances est déjà connu à l'avance.

Zone.js vs Signals : comparaison directe

j'attendsZone.js (détection de changement classique)Signaux
Comment il détecte les changementsInterceptez chaque API asynchrone globaleSuivi explicite des dépendances en lecture
Que vérifiez-vousL'arborescence entière (ou sous-arborescence avec OnPush)Uniquement les consommateurs réellement dépendants
Frais généraux du regroupement~30-35 Ko corrigésInclus dans le noyau, pas de frais supplémentaires
Compatibilité avec les bibliothèques tiercesRisque de conflits liés au patch singeAucun correctif global nécessaire
Prévisibilité du débogagePile de traces de correctifs croisésFlux de dépendance explicite et traçable
Courbe d'adoptionCela fonctionne "gratuitement" dès le premier jourNécessite une refactorisation de l'état existant

Que signifie « Angular sans zone » en pratique ?

Angulaire sans zone ne signifie pas seulement "utiliser des signaux dans les composants" - cela signifiesupprimer complètement Zone.jsdu bundle et confiez l’intégralité de la détection des changements au graphe de réactivité des signaux. Il est activé auprès d'un fournisseur dédié lors de la phase de bootstrap :

import { bootstrapApplication } from '@angular/platform-browser';
import { provideZonelessChangeDetection } from '@angular/core';

bootstrapApplication(AppComponent, {
  providers: [
    provideZonelessChangeDetection(),
    // ...altri provider
  ],
});

Une fois Zone.js supprimé, Angular n'a plus de moyen "automatique" de remarquer un changement générique -Tout va bienL'état qui doit être reflété dans l'interface utilisateur doit explicitement passer par un signal (ou unChangeDetectorRef.markForCheck()manuel dans les cas extrêmes). C’est pourquoi la migration n’est pas un simple drapeau à activer, mais un véritable changement de paradigme dans la gestion de l’État.

Guide pratique : migrer une application vers le sans zone

1. Vérifiez votre couverture OnPush

Si l'application utilise toujoursChangeDetectionStrategy.Defaultdans de nombreux composants, c'est le premier signe que l'état n'est pas explicitement géré : tout est transmis àSurPushc'est une condition préalable pratique avant même de supprimer Zone.js.

2. Remplacez l'état "implicite" par des signaux

// Prima: proprietà di classe normale, aggiornata via mutazione diretta
export class CartComponent {
  itemCount = 0;
  addItem(): void {
    this.itemCount++; // senza Zone.js, la UI non si aggiornerebbe
  }
}

// Dopo: signal, aggiornamento esplicito e tracciato
export class CartComponent {
  itemCount = signal(0);
  addItem(): void {
    this.itemCount.update(n => n + 1); // il template si aggiorna automaticamente
  }
}

3. Vérifiez les bibliothèques tierces

Certaines bibliothèques (en particulier les composants tiers plus anciens, ou le code qui suppose implicitement la présence de Zone.js pour "réveiller" Angular après un événement) peuvent cesser de mettre à jour correctement l'interface utilisateur en mode sans zone. Ils doivent être testés individuellement ou emballés dans un seulmarkForCheck()manuel aux points d'intégration.

4. Supprimez Zone.js du bundle

Une fois qu'il a été vérifié que tous les états passent par des signaux (ou une détection manuelle explicite des changements), Zone.js peut être supprimé des dépendances et du fichier polyfill, réduisant ainsi le bundle initial.

Quand il n’est PAS encore pratique de passer sans zone

  • Applications avec de nombreuses dépendances tierces obsolètes: Si les bibliothèques critiques supposent la présence de Zone.js, la migration nécessite des tests approfondis au cas par cas.
  • Bases de code très volumineuses avec un état géré de manière inégale: si l'état est dispersé entre les propriétés de classe directement mutées, les services avec RxJS non intégrés à Signals et la logique héritée, la refactorisation nécessaire est substantielle.
  • Des équipes peu familiarisées avec les signaux: sans zone amplifie les lacunes dans la gestion explicite de l'état - cela vaut la peine de consolider d'abord vos connaissances sur les signaux avec Zone.js toujours actif comme filet de sécurité.

Questions fréquemment posées

Dois-je supprimer Zone.js pour utiliser Signals ?

Non, les signaux fonctionnent parfaitement même avec Zone.js toujours actif — c'est l'étape intermédiaire la plus courante : adoptez d'abord Signals pour l'état, puis (éventuellement) supprimez Zone.js lorsque la couverture est terminée.

Les signaux remplacent-ils RxJS dans Angular ?

Non, ils couvrent différents cas d'usage : les signaux sont conçus pour des états synchrones locaux aux composants, RxJS reste l'outil idéal pour les flux asynchrones complexes (requêtes HTTP, WebSockets, combinaison de plusieurs événements dans le temps). Les utilitairesàSignal()EtàObservable()permettre aux deux modèles de coexister.

Zoneless est-il déjà prêt pour la production ?

La prise en charge sans zone est stable dans les versions récentes d'Angular, mais nécessite que l'ensemble de l'application (y compris les bibliothèques tierces utilisées) soit compatible avec un modèle explicite de détection des changements — il doit être évalué au cas par cas, ce n'est pas un simple commutateur universel.

Que se passe-t-il si j'oublie d'utiliser un signal pour un état qui doit mettre à jour l'interface utilisateur ?

En mode sans zone, l'interface utilisateur n'est tout simplement pas mise à jour jusqu'à ce qu'un autre déclencheur de détection de changement se produise (par exemple, un événement de modèle) : il s'agit d'un bug silencieux, c'est pourquoi la migration nécessite des tests approfondis sur chaque flux.

Les signaux améliorent-ils les performances même sans passer par une zone sans zone ?

Oui : même avec Zone.js toujours actif, les liaisons basées sur les signaux dans les modèles permettent à Angular de mettre à jour uniquement les nœuds DOM réellement dépendants, réduisant ainsi le travail de rendu par rapport aux liaisons classiques.

Dois-je réécrire l’intégralité de l’application pour adopter Signals ?

Non, les signaux et l'état « classique » peuvent coexister dans le même composant et la même application : vous pouvez migrer progressivement, composant par composant.


En résumé

Zone.js a permis à Angular d'offrir une détection automatique des modifications « gratuitement » depuis le premier jour, mais le prix est un modèle qui revérifie bien plus que nécessaire, avec un coût de bundle fixe et une fragilité connue dans l'intégration avec des bibliothèques tierces. Signals résout le problème à la racine, en suivant explicitement les dépendances au lieu d'intercepter chaque événement de navigateur asynchrone - et ouvre la voie à un Angular sans zone, plus léger et plus prévisible à déboguer. Si vous vous demandez quand utiliser Signals par rapport à RxJS dans la gestion quotidienne de l'état, ce guide renvoie directement àSignaux angulaires vs RxJS : quand utiliser l'un et quand l'autre.

💬 Notes des lecteurs

1 note

Écrire une note

Partagez votre avis, une suggestion ou un compliment

Dernières notes

Matteo
l&#x27;ho letto con attenzione, un riassunto abbastanza preciso.