{#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:
{#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.
# 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:
<!-- 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:
<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:
Noch nichts geladen.
Zusammenfassung
💡 Das Wichtigste
{#await}/{:then}/{:catch}rendert pending / Erfolg / Fehler.- Kurzform
{#await p then wert}überspringt den Ladezustand. - Das Promise im
$statehalten 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.