AngularAtlasAusg. 22.2

Kap. 16Fortgeschrittene UI & Performance71 / 75

Memory Leaks finden und beheben

Subscriptions, Timer und Listener, die ihre Komponente überleben – wie du sie in den DevTools findest und schließt.

~0 Min. Lesezeit Offizielle Doku

Ein Memory Leak in einer Angular-App bringt selten etwas zum Absturz. Der Tab wird im Laufe eines Nachmittags nur langsamer und schwerer: Jedes Mal, wenn eine Komponente zerstört wird, läuft etwas, das sie gestartet hat, weiter — eine Subscription, ein Timer, ein Listener auf window — und hält die ganze Komponente mit am Leben. Bezahlen müssen die Nutzer, die die App den ganzen Tag offen lassen.

Diese Seite zeigt die Quellen hinter fast jedem Leak, wie du jede einzelne schließt und wie du die übersehenen mit Chrome DevTools findest. Das Labor erzeugt echte Leaks in diesem Tab und räumt sie auf, wenn du die Seite verlässt.

Warum das wichtig ist
Eine Komponente zu zerstören stoppt nicht, was sie gestartet hat. Angular entfernt das DOM und führt die Destroy-Hooks aus; alles, worauf von etwas Langlebigerem verwiesen wird — einem Root-Service, einem Timer, einem globalen Listener —, zeigt weiterhin auf die Komponente und auf alles, worauf die Komponente zeigt.

Die üblichen Verdächtigen

Dieses Widget sieht harmlos aus und enthält die drei klassischen Leaks. Jeder Callback fängt this ein, und jeder wird von etwas gehalten, das länger lebt als das Widget: einem Root-Service, der Timer-Liste des Browsers, window. Öffne und schließe es im Labor ein paar Mal und beobachte, was zurückbleibt.

@Component({ selector: 'app-price-widget', template: `{{ price() }}` })
export class PriceWidget implements OnInit {
  private readonly prices = inject(PriceFeed); // ein Root-Service: lebt so lange wie die App
  protected readonly price = signal(0);

  ngOnInit() {
    // ✗ 1. der Feed hält den Callback, der Callback hält `this`, für immer
    this.prices.updates$.subscribe((p) => this.price.set(p));

    // ✗ 2. der Timer läuft weiter, nachdem die Komponente weg ist
    setInterval(() => this.refresh(), 5000);

    // ✗ 3. window überlebt jede Komponente
    window.addEventListener('resize', () => this.layout());
  }
}
LiveEin Widget öffnen und schließen, das vergisst aufzuräumen
Beim Destroy schließen:

Kein Widget auf der Seite.

zerstört, noch am Leben
0
gehaltener Speicher
0.00 MB
Zombie-Arbeit
0/s
Subscriptions
0
Timer
0
Listener
0
erstellte Widgets
0
Drücke „10-mal öffnen und schließen“ und bewege dann die Maus über die Seite: Zerstörte Widgets arbeiten weiter. Hake die drei Kästchen an, wiederhole es, und die Zähler bleiben bei null.

Jedes Widget hält einen 256-KB-Puffer, die Zahl „gehalten“ ist also Speicher, der wirklich nicht freigegeben werden kann, solange sein Zombie lebt. Die Kästchen gelten für Widgets, die nach dem Anhaken erstellt werden; „Zombies aufräumen“ stoppt, was die alten hinterlassen haben.

Jede Quelle schließen

Die Regel ist kurz: Für alles, was du startest, registrierst du im selben Moment ein Stopp. Für Observables hat Angular zwei Werkzeuge, die das für dich erledigen: toSignal() und takeUntilDestroyed(); für den Rest gibt es DestroyRef.onDestroy(). In host deklarierte Listener entfernt Angular; für mehrere Listener auf globalen Objekten schließt ein AbortController alle in einer Zeile.

import { Component, DestroyRef, inject, signal } from '@angular/core';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-price-widget',
  template: `{{ price() }}`,
  host: { '(window:resize)': 'layout()' }, // ✓ 3. Angular entfernt Host-Listener selbst
})
export class PriceWidget {
  private readonly prices = inject(PriceFeed);
  private readonly destroyRef = inject(DestroyRef);

  // ✓ 1a. toSignal meldet sich ab, wenn die Komponente zerstört wird
  protected readonly price = toSignal(this.prices.updates$, { initialValue: 0 });

  constructor() {
    // ✓ 1b. oder, wenn du wirklich subscribe() brauchst: takeUntilDestroyed
    this.prices.alerts$.pipe(takeUntilDestroyed()).subscribe((a) => this.notify(a));

    // ✓ 2. jeder Timer bekommt sein „Stopp“ direkt neben seinem „Start“ registriert
    const id = setInterval(() => this.refresh(), 5000);
    this.destroyRef.onDestroy(() => clearInterval(id));
  }
}
QuelleWas sie am Leben hältDie Lösung
subscribe()die Quelle hält deinen Callback, der Callback hält die KomponentetoSignal(), die async-Pipe oder takeUntilDestroyed()
setIntervalder Browser hält den Callback, bis der Timer gelöscht wirdDestroyRef.onDestroy(() => clearInterval(id))
addEventListenerwindow und document überleben jede Komponentehost: { '(window:resize)': … }, Renderer2.listen oder ein AbortController
Caches in Servicesein Root-Service lebt so lange wie die App, und seine Map auchden Eintrag beim Destroy löschen oder eine WeakMap mit dem Element als Schlüssel nutzen
Widgets von DrittanbieternCharts, Karten und Editoren registrieren eigene Listener und Timerihr destroy() / remove() in onDestroy aufrufen
// ✗ ein Root-Service, der sich Komponenten (oder ihr DOM) merkt, hält sie am Leben
@Service()
export class Tooltips {
  private readonly open = new Map<string, TooltipComponent>(); // nie gelöscht → Leak
}

// ✓ beim Destroy löschen oder den Garbage Collector per WeakMap entscheiden lassen
@Service()
export class Tooltips {
  private readonly anchors = new WeakMap<HTMLElement, TooltipComponent>(); // Schlüssel weg → Eintrag weg
}

Was nicht leakt

Nicht jedes subscribe() ist ein Problem. HttpClient-Anfragen completen nach der Antwort von selbst (mit takeUntilDestroyed() wird eine langsame Anfrage beim Verlassen auch abgebrochen). Die async-Pipe, toSignal(), output() und Host-Listener räumen hinter sich auf, ebenso effect() und computed(), die in einer Komponente erstellt wurden. Der Router räumt die Observables von ActivatedRoute auf. Was leakt, ist eine Subscription auf etwas, das nie completet und länger lebt als du: ein Store, ein Subject in einem Root-Service, interval, fromEvent(window, …), Router-Events.

Leaks mit Chrome DevTools finden

Ein Leak ist eine Zahl, die wächst, obwohl sie gleich bleiben sollte. Die Methode: Wiederhole eine Aktion, die nichts zurücklassen sollte — einen Dialog öffnen und schließen, auf eine Seite und zurück gehen —, und vergleiche den Speicher davor und danach.

  1. Wähle im Labor oben die drei Fixes ab. Öffne DevTools → das Panel Memory → unter Select profiling type Heap snapshot. Klicke auf das Papierkorb-Symbol (Collect garbage), dann auf Take snapshot.
  2. Drücke 10-mal öffnen und schließen und warte, bis es fertig ist. Wieder Collect garbage und Take snapshot.
  3. Stelle bei ausgewähltem Snapshot 2 das Menü oben links von Summary auf Comparison (gegen Snapshot 1) und sortiere nach # Delta.
  4. Tippe app-leaky-widget in Filter by class: +10, ein Host-Element pro geschlossenem Widget. Dann DOMTimer (+10 noch laufende Timer) und EventListener (+10 Listener). Auf der veröffentlichten Website sind Klassennamen minifiziert, LeakyWidget erscheint also nur, wenn du die App in der Entwicklung startest.
  5. Klicke auf eine Instanz und lies den Bereich Retainers unten: Klappe die Zeilen auf, um die Kette bis zu dem hinaufzugehen, was sie am Leben hält. Drücke Zombies aufräumen, nimm einen dritten Snapshot auf, und dieselben Zeilen stehen unter # Deleted.
  6. Direkter: Wähle unter Select profiling type Detached elements und drücke Get detached elements. Du bekommst ein <app-leaky-widget> pro geschlossenem Widget.

Für einen schnellen Check ohne Snapshots: Befehlsmenü (Ctrl/Cmd+Shift+P) → Show Performance monitor. Beobachte JS event listeners: Der Wert steigt bei jedem „10-mal“ mit abgewählten Fixes um 10 und sinkt erst nach dem Aufräumen.

Alle Panels Schritt für Schritt, mit Übungen und Stolperfallen (etwa DevTools, das selbst Objekte am Leben hält), findest du unter DevTools: ein Blick in deine App.

Ein Test, der den Leak beim nächsten Mal fängt

Hast du einen Leak behoben, mach es unmöglich, ihn zurückzubringen. Ein Subject weiß, ob noch jemand abonniert ist (observed); nach fixture.destroy() muss die Antwort false sein. Mehr zu Tests unter Testen mit Vitest.

import { TestBed } from '@angular/core/testing';
import { describe, expect, it } from 'vitest';

describe('PriceWidget', () => {
  it('stops listening to the feed when destroyed', () => {
    const feed = TestBed.inject(PriceFeed); // updates$ ist ein Subject im Service
    const fixture = TestBed.createComponent(PriceWidget);
    fixture.detectChanges();
    expect(feed.updates.observed).toBe(true);

    fixture.destroy();
    expect(feed.updates.observed).toBe(false); // niemand hört mehr zu
  });
});

Wann ja, wann nein

Lohnt die Jagd
  • Tabs, die stundenlang offen bleiben: Dashboards, Backoffice-Tools, Kassen, Chat.
  • Komponenten, die oft erstellt und zerstört werden: Dialoge, Listenzeilen, Tabs, wiederholt besuchte Routen.
  • Code, der globale Dinge abonniert: Stores, WebSockets, window-Events, Router-Events.
Keine Sorge wert
  • Eine einmalige HttpClient-Anfrage: Sie completet von selbst.
  • Subscriptions über die async-Pipe oder toSignal(): Sie werden für dich aufgeräumt.
  • Ein Root-Service, der für die ganze Lebensdauer der App etwas abonniert: Das ist Absicht, kein Leak.

Häufige Stolperfallen

  • subscribe() in ngOnInit, ohne Teardown, auf etwas aus einem Root-Service.
  • take(1) vertrauen. Emittiert die Quelle nie — der Nutzer geht vor dem ersten Wert —, wartet die Subscription ewig.
  • removeEventListener mit einer anderen Funktion. .bind(this) erzeugt jedes Mal eine neue Funktion, also wird nichts entfernt.
  • Komponenten oder DOM-Knoten in einer Service-Map. Der Service lebt ewig, und sie mit ihm.
  • Messen, ohne vorher Garbage Collection auszulösen. Der Heap steigt und fällt von selbst; vergleiche Snapshots, die nach Collect garbage aufgenommen wurden.

Spickzettel

subscribe() auf langlebige Quelle   takeUntilDestroyed() · toSignal() · async-Pipe
take(1) / first()                    nur sicher, wenn die Quelle emittieren WIRD; sonst wartet es ewig
setInterval / setTimeout-Ketten      DestroyRef.onDestroy(() => clearInterval(id))
Listener auf window / document       host: { '(window:resize)': … } · Renderer2.listen · AbortController
removeEventListener                  braucht DIESELBE Funktion: Referenz behalten, nicht zweimal .bind()
Root-Services                        keine Map von Komponenten oder DOM-Knoten; beim Destroy löschen oder WeakMap
Widgets von Drittanbietern           chart.destroy(), map.remove() in onDestroy
leakt nicht                          HttpClient (completet), async-Pipe, toSignal, Outputs, Host-Listener
auch sicher                          effect() und computed() in Komponenten: werden mit ihnen zerstört
DevTools                             Memory → Snapshot → N× wiederholen → GC → Snapshot → Comparison
Retainers lesen                      Subscriber / Timeout / EventListener = wer es am Leben hält
"Detached"                           DOM-Knoten, die aus der Seite entfernt, aber noch referenziert sind
in CI                                subject.observed === false nach fixture.destroy()

Kap. 16 · 0 von 4 abgeschlossen

Lektion abgeschlossen?

Markiere sie, dann erscheint sie auf deiner Karte: im Inhaltsverzeichnis und auf der Startseite.

Wird automatisch markiert, sobald du die ganze Lektion gelesen hast.

  1. Web Workers
  2. Riesige Listen: Virtual Scroll
  3. Moderne Animationen & View Transitions
  4. Memory Leaks finden und beheben
Deine ganze Karte ansehen

Alle 75 Seiten · tippen zum Filtern

  • 01Was ist neu in Angular 21 & 22Alle wichtigen Änderungen in v21 und v22 in Kürze, mit Link zur Seite, die sie jeweils erklärt.Start
  • 01Deine erste App, Schritt für SchrittEine Leseliste, von einer leeren Komponente bis zur fertigen App — Signals, @for, Inputs und Outputs, ein Service und ein Formular, Schritt für Schritt.Start
  • 01Schnelle Entscheidungen„Wohin damit?“, „Signal oder Observable?“, „Shared oder Feature?“ — kurze Antworten auf Alltagsfragen.Start
  • 01Angular-Interviewfragen60 echte Interviewfragen für Junior, Mid und Senior, mit der passenden Antwort, der Nachfrage und den Warnsignalen. Dazu ein Probeinterview.Start
  • 02Standalone & BootstrapWie eine App ohne NgModule startet: bootstrapApplication, app.config.ts, imports in der Komponente.Moderne Grundlagen
  • 02Data Binding & EventsInterpolation, Property- und Attribut-Bindings, Events mit $event und Tastenfiltern und wie [( )] aufgebaut ist — was in das DOM geht und was zurückkommt.Moderne Grundlagen
  • 02Control Flow: @if, @for, @switchDie Block-Syntax, die *ngIf/*ngFor/ngSwitch ersetzt, mit track, @empty und Exhaustive Checks.Moderne Grundlagen
  • 02@let und die neuen Template-AusdrückeLokale Variablen mit @let, Arrow Functions, Spread, Regex, instanceof, Kommentare in Tags.Moderne Grundlagen
  • 02@defer — Lazy Loading in TemplatesSchwere Komponenten nur laden, wenn sie gebraucht werden: Trigger, Prefetch, Placeholder, Loading, Error.Moderne Grundlagen
  • 02Class- & Style-BindingsWarum [class.x] und [style.x] ngClass und ngStyle abgelöst haben (mit automatischer Migration ab v21).Moderne Grundlagen
  • 02Komponenten-Styles & Kapselung:host, die drei Kapselungsmodi, Theming mit CSS-Variablen und warum ::ng-deep der letzte Ausweg ist.Moderne Grundlagen
  • 02Pipes: wann und wiePure vs. Impure Pipes, eigene Pipes und wie du zwischen Pipe, computed() und Methode wählst.Moderne Grundlagen
  • 03signal() und computed()Die reaktiven Grundbausteine: beschreibbarer Zustand, abgeleiteter Zustand, Gleichheit, untracked und Regeln zur Immutability.Signals & Reaktivität
  • 03effect() — wann ja, wann neinMit Signals synchronisierte Seiteneffekte: localStorage, Logging, imperative APIs. Und ihre Stolperfallen.Signals & Reaktivität
  • 03linkedSignal() — editierbarer abgeleiteter ZustandEin Signal, das sich zurücksetzt, wenn sich seine Quelle ändert, das du aber auch manuell setzen kannst.Signals & Reaktivität
  • 03resource, rxResource, httpResourceAsynchrone Daten als Signals: status, value, error, reload, automatischer Abbruch. Stabil seit v22.Signals & Reaktivität
  • 03debounced() — verzögerte SignalsDie „Debounce“-Variante eines Signals, ohne RxJS. Perfekt für die Suche.Signals & Reaktivität
  • 03Listen: suchen, filtern, sortieren, blätternEine Kette von computed-Signals, die nur neu berechnet, was sich geändert hat — mit den Filtern in der URL, damit ein Link dieselbe Ansicht öffnet.Signals & Reaktivität
  • 03Observables von null anWas ein Observable ist, subscribe und unsubscribe, die Operatoren, die du jede Woche brauchst, cold vs. hot — und wann ein Signal reicht.Signals & Reaktivität
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — und wann RxJS weiterhin die richtige Wahl bleibt.Signals & Reaktivität
  • 04input() und output()Inputs als Signals (required, transform, alias) und typisierte Outputs. Daten nach unten, Events nach oben.Komponenten: Kommunikation
  • 04model() — Two-Way-BindingBanana-in-a-Box [( )] mit einer einzigen API. Wann du es nutzt und wann input + output besser ist.Komponenten: Kommunikation
  • 04viewChild & contentChildQueries als Signals: viewChild, viewChildren, contentChild, contentChildren, die Option read.Komponenten: Kommunikation
  • 04Lifecycle & DestroyRefWelche Hooks in der Signals-Ära noch zählen, afterNextRender, DestroyRef und typisiertes ngOnChanges.Komponenten: Kommunikation
  • 04Content Projectionng-content mit select, mehrere Slots, Standardinhalt und die Falle der bedingten Projektion.Komponenten: Kommunikation
  • 04ng-template & ngTemplateOutletTemplates als Werte: Render Props in Angular, typisierter Kontext und Anpassen von Komponenten.Komponenten: Kommunikation
  • 05Smart vs. DumbContainer vs. Presentational: wer den Zustand hält, wer nur anzeigt und wie du die beiden sauber trennst.Komponenten-Design
  • 05Generische Komponenten <T>Eine korrekt typisierte DataTable<T> oder Select<T>, mit Templates für Zellen.Komponenten-Design
  • 05Dynamische KomponentenNgComponentOutlet, createComponent mit inputBinding/outputBinding und ein Dashboard, das aus einer Konfiguration gebaut wird.Komponenten-Design
  • 05Direktiven & Host-KompositionAttribut-Direktiven, die host: {}-Metadaten und die Directive Composition API (hostDirectives).Komponenten-Design
  • 05Eigene Formular-ControlsFormValueControl (Signal Forms) vs. ControlValueAccessor: eine Sternebewertung, in beiden Varianten.Komponenten-Design
  • 05Change DetectionOnPush ist ab v22 der Standard, zone.js entfällt ab v21. Was das Rendering auslöst und wie du dir nicht die Finger verbrennst.Komponenten-Design
  • 06inject() & @Service()Der neue @Service()-Decorator ab v22, inject() vs. Konstruktor und der Injection-Kontext.Dependency Injection
  • 06Provider & die Injector-HierarchieRoot vs. Route vs. Komponente, useClass/useValue/useFactory/useExisting und die Modifier optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Typisierte Konfiguration, provideFeature()-Funktionen, makeEnvironmentProviders und Initializer.Dependency Injection
  • 06injectAsync() — Lazy ServicesLade einen schweren Service erst, wenn du ihn brauchst, mit Prefetch im Leerlauf.Dependency Injection
  • 07Ordnerstrukturcore / shared / features, was in welchen Ordner gehört und wie ein Feature von innen aussieht.Architektur der Anwendung
  • 07Shared vs. FeatureWann du eine Komponente nach Shared verschiebst und (vor allem) wann NICHT. Eine konkrete Checkliste.Architektur der Anwendung
  • 07Interfaces & ModelleInline-Interface oder eigene Datei? DTO vs. Domänenmodell, type vs. interface, wohin damit.Architektur der Anwendung
  • 07State Management mit SignalsEinfache Signal-Stores, Fassaden, lokaler vs. globaler Zustand und wann du NgRx brauchst.Architektur der Anwendung
  • 07Styleguide & NamensgebungDie aktuellen offiziellen Konventionen: Dateinamen ohne Suffixe, protected, readonly, Reihenfolge der Member.Architektur der Anwendung
  • 07Barrels, Aliase & Grenzenindex.ts, Pfad-Aliase, die öffentliche API eines Features und Abhängigkeitsregeln, die sich automatisch prüfen lassen.Architektur der Anwendung
  • 07Fehler: @boundary & ErrorHandlerDer neue @boundary-Block ab v22.2, der globale ErrorHandler, HTTP-Fehler und Fehler aus resource.Architektur der Anwendung
  • 08Modernes Routing & Lazy LoadingloadComponent, Child Routes, Parameter als Inputs und Parameter-Vererbung (neuer Standard in v22).Routing
  • 08Guards & ResolvercanActivate, canMatch, canDeactivate und resolve als Funktionen, mit Redirects über UrlTree / RedirectCommand.Routing
  • 09Signal Forms — die GrundlagenFormulare auf Basis von Signals: form(), [formField], schemabasierte Validierung. Stabil seit v22.Formulare
  • 09Signal Forms — fortgeschrittenEigene und feldübergreifende Validierung, async/HTTP mit Debounce, dynamische Listen, disabled/hidden, wiederverwendbare Schemas.Formulare
  • 09Typisierte Reactive FormsTypisierte FormGroup, nonNullable, FormArray — und wie sie neben Signal Forms bestehen.Formulare
  • 10HttpClient, Interceptors & die API-SchichtHttpClient ohne Setup (v21), Fetch als Standard (v22), funktionale Interceptors und eine API-Schicht mit DTO-Mapping.HTTP & Daten
  • 11Performance — eine ChecklisteWas wirklich zählt: OnPush + Signals, track, @defer, Lazy Routes, Bilder, Bundles und Hydration.Qualität & Performance
  • 11Testen mit VitestVitest ist ab v21 der Standard-Runner. TestBed, Komponenten mit Signals, Services, HTTP und Harnesses.Qualität & Performance
  • 11DevTools: ein Blick in deine AppChrome DevTools und Angular DevTools Schritt für Schritt: was jedes Panel zeigt, mit Übungen, die auf dieser Website funktionieren.Qualität & Performance
  • 11Angular AriaHeadless, barrierefreie Komponenten, die du nach Belieben stylst: Tabs, Accordion, Menü, Listbox...Qualität & Performance
  • 12SSR, Prerendering & Render ModesWann auf dem Server gerendert wird, wann beim Build und wann nur im Browser: RenderMode pro Route, app.routes.server.ts und die echten Kosten.SSR & Hydration
  • 12Hydration: Event Replay & inkrementellWie der Browser das Server-HTML übernimmt, ohne es neu zu rendern: vollständige Hydration, Event Replay, @defer (hydrate on …) und Mismatch-Fehler.SSR & Hydration
  • 12Servertauglicher Codewindow gibt es auf dem Server nicht: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, der HTTP-Cache und PendingTasks.SSR & Hydration
  • 13Micro FrontendsWann es sich lohnt, eine App in mehrere Deployments aufzuteilen und wann es nur Komplexität ist: Native Federation, Module Federation, iframes, Web Components.Architektur im großen Maßstab
  • 13Web Components mit Angular ElementscreateCustomElement: eine Angular-Komponente, die überall als HTML-Tag nutzbar ist, plus Kommunikation zwischen Apps über Events und BroadcastChannel.Architektur im großen Maßstab
  • 13Monorepo, Bibliotheken & GrenzenEin Workspace mit mehreren Apps und Bibliotheken: ng generate library, Nx, Secondary Entry Points, Publishing und Abhängigkeitsregeln.Architektur im großen Maßstab
  • 13Hexagonale Architektur (Ports & Adapters)Eine Domäne ohne Angular, Ports als abstrakte Klassen und austauschbare Adapter: HTTP, localStorage oder In-Memory, ohne die UI anzufassen.Architektur im großen Maßstab
  • 14Signals unter der HaubeDer reaktive Graph: Producer und Consumer, Push-Pull, warum computed lazy und glitch-frei ist, das Diamond-Problem und wann Effects laufen.Fortgeschrittene Reaktivität
  • 14Fortgeschrittenes RxJS: Operatoren höherer OrdnungswitchMap, mergeMap, concatMap und exhaustMap an einem Live-Diagramm, dazu Retry mit Backoff, shareReplay und wie du Leaks vermeidest.Fortgeschrittene Reaktivität
  • 14NgRx SignalStoreState Management im großen Stil auf Signals: withState, withComputed, withMethods, rxMethod, Entities und Hooks — und wann ein einfacher Store reicht.Fortgeschrittene Reaktivität
  • 14Zustandsautomaten mit SignalsKeine unmöglichen Zustände mehr: ein typisierter Automat auf Signals, mit Übergängen, Guards und einem Live-Zustandsdiagramm.Fortgeschrittene Reaktivität
  • 15WebSockets: Echtzeit, die das Netz überstehtEin typisierter Socket als Signals: Reconnect mit Backoff und Jitter, Heartbeat, ein Postausgang im Offline-Modus und SSR-Sicherheit.Echtzeit & offline
  • 15Optimistische Updates & RollbackEine sofortige UI, die ehrlich bleibt: Snapshot und Rollback, Antworten in falscher Reihenfolge, Idempotenzschlüssel.Echtzeit & offline
  • 15Offline-first: Service Worker & CachingDer Angular Service Worker: Caching-Strategien, Update-Hinweise und ein Postausgang für Änderungen, die offline entstehen.Echtzeit & offline
  • 16Web WorkersSchwere Berechnungen, ohne die UI zu blockieren: ein echter Worker in der Seite, Message Passing und wann es sich nicht lohnt.Fortgeschrittene UI & Performance
  • 16Riesige Listen: Virtual Scroll100.000 Zeilen ohne Ruckeln: CDK Virtual Scroll, itemSize, trackBy und die Alternativen (Paginierung, Infinite Scroll).Fortgeschrittene UI & Performance
  • 16Moderne Animationen & View Transitionsanimate.enter und animate.leave statt des veralteten @angular/animations, CSS-Transitions und View Transitions bei der Navigation.Fortgeschrittene UI & Performance
  • 16Memory Leaks finden und behebenSubscriptions, Timer und Listener, die ihre Komponente überleben – wie du sie in den DevTools findest und schließt.Fortgeschrittene UI & Performance
  • 17Sicherheit: XSS, Sanitizing & CSPWas Angular automatisch gegen XSS tut, wann bypassSecurityTrust gefährlich wird, dazu CSP mit Nonce, Trusted Types und XSRF.Sicherheit & Globalisierung
  • 17Authentifizierung: Tokens & RefreshEin Interceptor, der das Token anhängt, bei 401 einmal erneuert und die wartenden Requests wiederholt — dazu, wo du das Token aufbewahrst.Sicherheit & Globalisierung
  • 17OAuth 2.1 & OpenID Connect mit PKCEDer Authorization-Code-Flow mit PKCE Schritt für Schritt: Verifier und Challenge, State und Nonce, das ID-Token und warum ein BFF sicherer ist.Sicherheit & Globalisierung
  • 17Internationalisierung (i18n)$localize, das i18n-Attribut, ICU plural/select, ein Build pro Sprache vs. Übersetzungen zur Laufzeit und Formatierung nach Locale.Sicherheit & Globalisierung