While working on my first Svelte project for a Wunderdog customer, I was caught by surprise—not by Svelte being very effective and fun to work with, that part I already knew.
What surprised me was the order in which Svelte was executing JavaScript code, especially when mixing up asynchronous functions, reactive statements, and onMount.
For example, take a look at this Svelte component, or head to the Svelte REPL. In which order will these console logs appear? Go ahead and write it down before you continue reading.
<script>
import { onMount } from 'svelte'
const fetchData = async () => {
console.log('1. fetchData')
}
console.log('2. started')
fetchData().then(() => console.log('3. fetched'))
$: console.log('4. reactive')
console.log('5. continued')
onMount(() => {
console.log('6. onMount')
})
console.log('7. after mount')
</script>
The Answer
2. started
1. fetchData
5. continued
7. after mount
4. reactive
6. onMount
3. fetched
Why is that? Let’s investigate
2. started
The fetchData
constant is assigned to an asynchronous function. The function isn’t called yet, so it doesn’t log anything at the moment. Hence, the first log that appears in the console is 2. started
.
1. fetchData
Next, the fetchData
function is called, thus 1. fetchData
is logged to the console. The callback .then(() => console.log('3. fetched'))
isn’t called just yet—it’s added to the browser’s message queue, and will be called once the event loop reaches it, a bit later.
5. continued
Shouldn’t 4. reactive
be logged now? That’s what I thought, but turns out I was wrong. According to the Svelte docs:
Reactive statements run after other script code and before the component markup is rendered, whenever the values that they depend on have changed.
Indeed, other script code hasn’t finished running yet. Therefore, this reactive statement isn’t executed at this time, and the next console log is 5. continued
.
7. after mount
7. after mount
is logged to the console. That’s because the callback in onMount
will only be called once the component is first rendered, and that hasn’t happened yet.
4. reactive
Now we hit that sweet spot after other script code has been executed, and before the component markup is rendered. This means it’s time to execute that reactive statement, thus logging 4. reactive
to the console.
6. onMount
At this point there is no more script code to execute and the component is rendered. Thus, the onMount
callback is called and 6. onMount
is logged to the console.
3. fetched
What about the callback to our asynchronous function, remember that? Oh yeah, says the event loop, as it handles the message queue. The callback is executed, and finally, 3. fetched
is logged to the console.
Done
While I find Svelte to be very intuitive and developer friendly, the script execution order can be a bit puzzling when using asynchronous functions and reactive statements. I hope that this post has helped you to understand this issue and to squash your bugs.
Photo by Cookie the Pom on Unsplash
Top comments (1)
thank for stepping through this, it confirms that my habit of putting all reactive statements at the end of the script block is meaningful