Resolve promises in Svelte templates
By Flavio Copes
Learn how to resolve promises directly in Svelte templates with the await block, showing different markup for the waiting, then, and catch states.
Svelte lets you resolve promises directly in the template, using the {#await} block. You define one piece of markup for while the promise is pending, one for when it resolves, and one for when it rejects.
Promises are an awesome tool we have at our disposal to work with asynchronous events in JavaScript. The relatively recent introduction of the await syntax in ES2017 made using promises even simpler.
But in a component, promises usually mean bookkeeping. You create a state variable for the loading flag, one for the data, one for the error, and you update them by hand. The {#await} block removes all of that.
How the await block works
We define a promise, and using the {#await} block we wait for it to resolve.
Once the promise resolves, the result is passed to the {:then} block:
<script>
const fetchImage = (async () => {
const response = await fetch('https://dog.ceo/api/breeds/image/random')
return await response.json()
})()
</script>
{#await fetchImage}
<p>...waiting</p>
{:then data}
<img src={data.message} alt="Dog image" />
{/await}
While the fetch is running, the page shows the “…waiting” paragraph. As soon as the promise resolves, Svelte swaps in the image.
Notice we invoke the async function immediately. The fetchImage variable holds a promise, not a function. The {#await} block wants a promise.
Handling errors
You can detect a promise rejection by adding a {:catch} block:
{#await fetchImage}
<p>...waiting</p>
{:then data}
<img src={data.message} alt="Dog image" />
{:catch error}
<p>An error occurred!</p>
{/await}
The error variable holds the rejection value, so you can also print error.message if you want details.
The shorthand syntax
If you don’t need the loading state, you can use a shorter form:
{#await fetchImage then data}
<img src={data.message} alt="Dog image" />
{/await}
Nothing renders until the promise resolves. This is handy when the data arrives fast and a flash of “loading” text would just add noise.
Be careful with re-fetching
One thing that trips people up: the block tracks the promise stored in the variable. Calling fetch() again somewhere does nothing to the template.
To re-run the block, assign a new promise to the variable. Svelte notices the assignment, goes back to the pending state, and waits for the new promise to settle.
Run the example: https://svelte.dev/repl/70e61d6cc91345cdaca2db9b7077a941