AngularAtlasAusg. 22.2

Kap. 15Echtzeit & offline66 / 75

Optimistische Updates & Rollback

Eine sofortige UI, die ehrlich bleibt: Snapshot und Rollback, Antworten in falscher Reihenfolge, Idempotenzschlüssel.

Architektur ~0 Min. Lesezeit

Auf den Server zu warten, bevor sich der Bildschirm ändert, ist ehrlich, aber langsam: Ein Like, das nach 400 ms erscheint, fühlt sich kaputt an. Ein optimistisches Update ändert die Oberfläche sofort, geht davon aus, dass die Anfrage gelingt, und nimmt die Änderung zurück, wenn nicht.

Die Idee passt in einen Satz. An den Details gehen Apps kaputt: was genau du beim Fehlschlag wiederherstellst, was passiert, wenn zwei Antworten in falscher Reihenfolge ankommen, und wie der Server verhindert, dass er dieselbe Aktion beim Retry zweimal ausführt.

Warum das wichtig ist
Fast alle Anfragen gelingen. Alle Nutzer wegen der wenigen Fehlschläge warten zu lassen, ist ein schlechter Tausch — aber eine optimistische Oberfläche, die lügt, wenn doch etwas scheitert, ist schlimmer: Der Nutzer geht in dem Glauben, die Änderung sei gespeichert.

Das Muster: merken, anwenden, bestätigen oder zurücknehmen

Drei Schritte. Den aktuellen Wert merken, ihn lokal ändern, die Anfrage senden. Bei Erfolg ersetzt die Antwort des Servers deine Vermutung — sie kann abweichen (eine ID, ein Zeitstempel, bereinigter Text). Bei einem Fehler stellst du den gemerkten Wert wieder her und sagst es dem Nutzer: Ein Wert, der kommentarlos zurückspringt, sieht aus wie ein Bug.

import { Service, inject, signal } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { TodoApi, type Todo } from './todo-api';

@Service()
export class TodoStore {
  private readonly api = inject(TodoApi);
  readonly todos = signal<readonly Todo[]>([]);
  readonly error = signal<string | null>(null);

  async toggle(id: string): Promise<void> {
    const before = this.todos().find((t) => t.id === id);
    if (!before) return;

    this.patch(id, { done: !before.done }); // 1. der Bildschirm ändert sich JETZT
    try {
      const saved = await firstValueFrom(this.api.update(id, { done: !before.done }));
      this.patch(id, saved); // 2. die Version des Servers gewinnt (Zeitstempel, normalisierter Text...)
    } catch {
      this.patch(id, { done: before.done }); // 3. NUR dieses Element zurücknehmen...
      this.error.set(`„${before.title}“ konnte nicht gespeichert werden. Rückgängig gemacht.`); // ...und es sagen
    }
  }

  private patch(id: string, change: Partial<Todo>): void {
    this.todos.update((list) => list.map((t) => (t.id === id ? { ...t, ...change } : t)));
  }
}
LiveOptimistisch vs. pessimistisch, mit einem Server, der ausfällt

Die Oberfläche

Auf dem Server gespeichert

  • Release Notes schreiben
  • Den Pull Request reviewen
  • Abhängigkeiten aktualisieren
  • Den wackligen Test reparieren
Wirkung sichtbar nach
—
Anfragen
0
fehlgeschlagen
0
Oberfläche ≠ Server
0
Hake Aufgaben in beiden Modi ab und vergleiche, wann du die Wirkung siehst. Wähle dann „die ganze Liste“ und drücke „Szenario abspielen“.

Nimm zurück, was du geändert hast, nicht die ganze Liste

Einen Snapshot der ganzen Liste zu sichern ist die verlockendste Variante — und falsch, sobald zwei Anfragen unterwegs sind. Der Snapshot der ersten Anfrage enthält die zweite Änderung nicht; scheitert die erste, löscht das Wiederherstellen auch eine Änderung, die der Server bereits gespeichert hat. Das Szenario in der Demo macht genau das: Oberfläche und Server sind sich am Ende uneinig, und nichts bringt sie wieder zusammen. Nimm pro Element zurück oder wende die Gegenoperation an.

// ✗ Ein Snapshot der GANZEN Liste erfasst auch die anderen Änderungen, die noch unterwegs sind
async toggle(id: string) {
  const snapshot = this.todos(); // aufgenommen vor dem nächsten Klick des Nutzers...
  this.patch(id, { done: !this.find(id).done });
  try {
    await firstValueFrom(this.api.update(id, ...));
  } catch {
    this.todos.set(snapshot); // ...also wird auch eine Änderung zurückgenommen, die der Server BEREITS gespeichert hat
  }
}

Optimistisches Anlegen braucht noch einen Schritt. Das neue Element hat noch keine echte ID, also bekommt es eine temporäre, die du ersetzt, wenn der Server antwortet. Bis dahin müssen Änderungen an diesem Element warten oder die temporäre ID verwenden, die der Server nicht kennt.

async add(title: string): Promise<void> {
  const temp: Todo = { id: `tmp-${crypto.randomUUID()}`, title, done: false };
  this.todos.update((list) => [...list, temp]);
  try {
    const saved = await firstValueFrom(this.api.create({ title }));
    // die temporäre ID verschwindet: jede spätere Bearbeitung nutzt die echte
    this.todos.update((list) => list.map((t) => (t.id === temp.id ? saved : t)));
  } catch {
    this.todos.update((list) => list.filter((t) => t.id !== temp.id));
    this.error.set(`„${title}“ wurde nicht hinzugefügt.`);
  }
}

Antworten in der falschen Reihenfolge

Schalte eine Einstellung schnell ein, aus und wieder ein. Drei Anfragen gehen raus, und nichts garantiert die Reihenfolge, in der die Antworten zurückkommen. Wenn jede Antwort den Zustand überschreibt, gewinnt die zuletzt angekommene Antwort — nicht die letzte Wahl des Nutzers.

LiveDrei schnelle Klicks, zufällige Latenz

Jeder Klick sendet eine Anfrage. Ihr Balken endet, wenn die Antwort ankommt.

Deine Wahl
off
Letzte Antwort gewinnt
off …
Nur die neueste Anfrage
off …

„Letzte Antwort gewinnt“ lag 0-mal von 0 falsch.

Drücke ein paar Mal „Dreimal klicken“. Jede Anfrage dauert 0,3–2 s; beobachte die Ankunftsreihenfolge und den Zähler darunter.

Zwei Lösungen für zwei verschiedene Probleme. Nur die neueste: Jede Anfrage bekommt eine Nummer, und nur die Antwort auf die neueste darf schreiben — das repariert die Oberfläche. Aber auch der Server kann die Anfragen vertauscht erhalten haben. Wenn der Endzustand auf dem Server zählt, serialisiere die Schreibvorgänge mit concatMap (eine Anfrage nach der anderen, in Klickreihenfolge) oder sende eine Version, die der Server prüft. Bei Suchen, wo nur die letzte zählt, bricht switchMap die alten ab; siehe Higher-Order-Operatoren.

private latest = 0;
readonly enabled = signal(false); // was der Nutzer sieht (optimistisch)
private readonly confirmed = signal(false); // was der Server zuletzt bestätigt hat

async setNotifications(on: boolean): Promise<void> {
  const id = ++this.latest;
  this.enabled.set(on);
  try {
    const saved = await firstValueFrom(this.api.saveSettings({ notifications: on }));
    this.confirmed.set(saved.notifications);
    // eine ältere Antwort, die spät ankommt, darf eine neuere Wahl nicht überschreiben
    if (id === this.latest) this.enabled.set(saved.notifications);
  } catch {
    if (id === this.latest) this.enabled.set(this.confirmed());
  }
}

Idempotenz: eine Aktion, genau einmal angewendet

Optimistische Oberflächen wiederholen Anfragen, und hier liegt die Falle: Die Anfrage kam an, die Bestellung wurde angelegt, nur die Antwort ging verloren. Ein Retry legt eine zweite Bestellung an. Die Lösung ist ein Idempotency-Key: eine UUID, einmal pro Nutzeraktion erzeugt und mit jedem Retry mitgeschickt. Der Server merkt sich verarbeitete Schlüssel und liefert bei einer Wiederholung das ursprüngliche Ergebnis, statt die Arbeit erneut zu tun.

import { HttpClient, HttpContext, HttpContextToken, HttpInterceptorFn } from '@angular/common/http';
import { retry } from 'rxjs';

export const IDEMPOTENCY_KEY = new HttpContextToken<string | null>(() => null);

/** Der Schlüssel reist im Kontext der Anfrage mit und wird zum Header. */
export const idempotencyInterceptor: HttpInterceptorFn = (req, next) => {
  const key = req.context.get(IDEMPOTENCY_KEY);
  return next(key ? req.clone({ setHeaders: { 'Idempotency-Key': key } }) : req);
};

// Ein Schlüssel pro NUTZERAKTION, wiederverwendet bei jedem Retry dieser Aktion.
placeOrder(order: Order) {
  const key = crypto.randomUUID();
  return this.http
    .post<OrderConfirmation>('/api/orders', order, {
      context: new HttpContext().set(IDEMPOTENCY_KEY, key),
    })
    .pipe(retry({ count: 3, delay: 1000 })); // gleiches Observable → gleicher Kontext → gleicher Schlüssel
}

Der Schlüssel gehört zur Aktion des Nutzers, nicht zur HTTP-Anfrage: Erzeuge ihn, wenn der Nutzer den Button drückt, nicht in einem Interceptor, der bei jedem Retry einen neuen machen würde. Retries selbst behandelt HttpClient und Interceptoren.

Wann ja, wann nein

Wann ja
  • Häufige, billige Aktionen, die fast immer gelingen: Likes, Häkchen, als gelesen markieren.
  • Änderungen, die sich leicht zurücknehmen lassen: Umsortieren, Umbenennen, die Menge im Warenkorb.
  • Oberflächen, in denen man die Latenz bei jedem Klick spürt: Listen, Boards, Editoren.
Wann nein
  • Zahlungen und alles mit Geld: Der Nutzer braucht eine echte Bestätigung.
  • Unumkehrbare Aktionen: eine E-Mail senden, endgültig löschen, veröffentlichen.
  • Validierung, die auf dem Server oft scheitert (ein vergebener Benutzername): Du würdest ständig zurücknehmen.

Häufige Stolperfallen

  • Stilles Rollback. Das Häkchen verschwindet ohne Meldung; der Nutzer hält die App für kaputt oder merkt es gar nicht.
  • Ein Snapshot der ganzen Liste. Er nimmt auch andere laufende Änderungen zurück, darunter solche, die der Server schon gespeichert hat.
  • Die letzte Antwort gewinnt. Eine alte, spät ankommende Antwort überschreibt die neueste Wahl. Nummeriere die Anfragen.
  • Retry ohne Idempotenzschlüssel. Aus einer verlorenen Antwort wird eine doppelte Bestellung.
  • Nie mit dem Server abgleichen. Temporäre IDs, die nie ersetzt werden, normalisierter Text, der nie zurückkommt: Die Oberfläche driftet langsam von den Daten weg.

Spickzettel

optimistisches Update  Snapshot → sofort anwenden → senden → Serverversion | Rollback + Meldung
Rollback               nur, was diese Anfrage geändert hat (das Element / die Gegenoperation)
nicht die ganze Liste  ein Listen-Snapshot nimmt auch andere laufende Anfragen zurück
Antwort des Servers    ersetzt die lokale Vermutung (IDs, Zeitstempel, normalisierter Text)
temporäre IDs          tmp-uuid, bis „create“ antwortet, dann durch die echte ID ersetzen
vertauschte Antworten  ID pro Anfrage: nur die neueste darf schreiben (newest-only)
Schreiben in Reihe     concatMap: eine nach der anderen, in der Reihenfolge der Klicks
Lesen                  switchMap: alte Suche abbrechen, neue behalten
Retries                Idempotency-Key = eine UUID pro Nutzeraktion, bei jedem Retry gleich
nie optimistisch       Zahlungen, unumkehrbare Aktionen, Validierung, die oft scheitert
Rollback ohne Meldung = eine UI, die kaputt wirkt

Kap. 15 · 0 von 3 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. WebSockets: Echtzeit, die das Netz übersteht
  2. Optimistische Updates & Rollback
  3. Offline-first: Service Worker & Caching
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