Awaiting Promises in Markup
Handling pending, resolved, and error states of a promise directly in your template with {#await}.
2 menit membaca
Fetching data almost always means juggling three states: still loading, loaded successfully, or failed. You could track that with a few $state variables and {#if} chains, but Svelte has a block built specifically for a promise's lifecycle: {#await}.
<script>
let promise = $state(fetchUser());
function fetchUser() {
return fetch('/api/user').then((r) => r.json());
}
</script>
{#await promise}
<p>Loading…</p>
{:then user}
<p>Welcome, {user.name}!</p>
{:catch error}
<p>Failed to load: {error.message}</p>
{/await}The block reacts to whichever state the promise is currently in: {#await promise} shows while it's pending, {:then user} runs once it resolves (with user bound to the resolved value), and {:catch error} runs if it rejects. Nothing else in your code needs to track "is this loading" as a separate boolean — the promise's own state is the state.
Skipping the loading state
If you don't want a loading message — say, the data usually resolves fast enough not to need one — omit the first block:
{#await promise then user}
<p>Welcome, {user.name}!</p>
{/await}This shorthand renders nothing while pending and jumps straight to the then branch once resolved.
Re-running on a new promise
{#await} tracks the promise value itself, not a fetch call — so to load new data, assign a new promise to the variable it's watching:
<script>
let userId = $state(1);
let promise = $derived(fetchUser(userId));
function fetchUser(id) {
return fetch(`/api/users/${id}`).then((r) => r.json());
}
</script>
<button onclick={() => userId++}>Next user</button>
{#await promise}
<p>Loading…</p>
{:then user}
<p>{user.name}</p>
{/await}Because promise is $derived from userId, incrementing userId creates a fresh promise, and {#await} picks it up automatically — reverting to its pending state and running the whole cycle again.
When to reach for it
{#await} is a good fit for a single, page-level fetch tied directly to the markup that displays it. For anything more involved — retries, caching, requests shared across several components — you'll usually want a dedicated data-fetching pattern (or library) that hands {#await} an already-managed promise, rather than trying to make the block itself do that extra work.