S SvelteKurs
M4 · Template-Logik

{#await} — Promises im Markup

Lade-, Erfolgs- und Fehlerzustand eines Promise direkt in der Vorlage rendern — ohne manuelles Zustands-Jonglieren.

Der {#await}-Block

Ein {#await}-Block rendert die drei Phasen eines Promise: solange es noch läuft (pending), wenn es erfolgreich aufgelöst wurde (then) und wenn es abgelehnt wurde (catch). Du musst keinen Lade- oder Fehler-State von Hand verwalten — Svelte übernimmt das:

svelte
{#await promise}
  <p>Lädt …</p>
{:then wert}
  <p>Ergebnis: {wert}</p>
{:catch fehler}
  <p>Fehler: {fehler.message}</p>
{/await}

Der Wert nach {:then} ist das aufgelöste Ergebnis, der nach {:catch} das Fehlerobjekt. Beide sind nur im jeweiligen Zweig verfügbar.

🛤️ Rails-Vergleich: synchrones vs. clientseitiges Laden

In Rails wird typischerweise vor dem Rendern gewartet: Der Controller holt die Daten, und erst wenn alles da ist, geht die fertige HTML-Seite raus. Einen „Lädt …"-Zustand gibt es im View nicht.

nachrichten_controller.rb ruby
# Rails: das Warten passiert VOR dem Rendern
class NachrichtenController < ApplicationController
  def index
    @nachrichten = Nachricht.all   # blockiert bis fertig
    # erst wenn alles da ist, wird die View gerendert
  end
end

{#await} ist das Gegenstück fürs clientseitige Nachladen: Die Seite ist schon da, und ein Teil wird nachträglich gefüllt — inklusive sichtbarem Ladeindikator und Fehlerbehandlung, ganz ohne extra JavaScript.

Kurzform ohne pending-Zweig

Wenn dich der Ladezustand nicht interessiert, lässt du den pending-Block weg und schreibst {#await … then} in eine Zeile. Dann bleibt der Bereich leer, bis das Promise aufgelöst ist:

svelte
<!-- Ohne pending-Block: zeigt erst NACH dem Auflösen etwas -->
{#await promise then wert}
  <p>Ergebnis: {wert}</p>
{/await}

Analog kannst du auch nur am Fehler interessiert sein — dann genügen then und catch. Alle Zweige außer dem Promise selbst sind optional.

Promise neu auslösen

{#await} reagiert auf das Promise als Wert. Legst du das Promise in $state und weist ein neues zu, startet der Block automatisch neu — zurück in den pending-Zustand. So baust du einen „Neu laden"-Button:

Nachrichten.svelte svelte
<script lang="ts">
  let daten = $state<Promise<string> | null>(null);

  function laden() {
    // Neues Promise zuweisen -> {#await} startet neu
    daten = fetch('/api/nachrichten').then((r) => r.text());
  }
</script>

<button onclick={laden}>Neu laden</button>

{#if daten}
  {#await daten}
    <p>Lädt …</p>
  {:then text}
    <p>{text}</p>
  {:catch e}
    <p>Fehler: {e.message}</p>
  {/await}
{/if}

ℹ️ Warum das {#if daten} drumherum?

Solange noch nichts geladen wurde, ist daten hier null — und null ist kein Promise. Das {#if} sorgt dafür, dass der {#await}-Block erst erscheint, wenn tatsächlich ein Promise vorliegt.

Live ausprobieren

Der Button startet ein Promise, das nach kurzer Zeit zufällig gelingt oder fehlschlägt. Beobachte den Wechsel zwischen Lade-, Erfolgs- und Fehlerzustand — und drücke mehrmals, um das Promise neu auszulösen:

▶ Daten nachladen · Interaktiv

Noch nichts geladen.

Zusammenfassung

💡 Das Wichtigste

  • {#await} / {:then} / {:catch} rendert pending / Erfolg / Fehler.
  • Kurzform {#await p then wert} überspringt den Ladezustand.
  • Das Promise im $state halten und neu zuweisen löst den Block neu aus.
  • Ideal fürs clientseitige Nachladen — das Gegenstück zum synchronen Rails-Rendering.

🎯 Probier es selbst

Deaktiviere den Button während des Ladens (setze ein zweites $state-Flag wie laedt, oder nutze disabled), damit man nicht doppelt klickt. Erweitere die Demo anschließend um einen Zähler, der zeigt, wie oft erfolgreich geladen wurde.