Check out a free preview of the full Svelte Fundamentals course

The "Lifecycle Q&A" Lesson is part of the full, Svelte Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Rich answers student questions regarding if bindings are synchronous, how await differs from onMount, how onMount impacts performance, ways to organize multiple await blocks, and if there is a way to use Promise.all for multiple await blocks. A more in-depth explanation of tick and what the this keyword is referring to are also covered in this segment.

Preview
Close

Transcript from the "Lifecycle Q&A" Lesson

[00:00:00]
>> One quick question about bindings, are bindings synchronous?
>> Okay, so there was a question about whether bindings are synchronous or not, and that's a really interesting question. The answer is they update the state synchronously. So when you have a bind value on a text input, it is essentially as if you had an on input event handler, and you are assigning to the value inside that event handler.

[00:00:27]
So in that sense, it is synchronous. But like all state updates, that will be batched, and it won't update the DOM until we've waited for the current microtask. Now, because you're interacting with the element yourself, the binding isn't gonna need to update the input, if that makes sense.

[00:00:53]
Because if you have an input and you type in some text, the input already has that text. So we don't need to wait for the binding to go all the way around and then get fed back into the input as it were because it's already in the desired end state.

[00:01:08]
But the update to anything else in the DOM that references that piece of state, that will happen after the current microtask. Getting super in the weeds here, but hopefully that made sense.
>> How does using await blocks differ to using onMount as below, and so he's got let data onMount in the brackets async.

[00:01:34]
The data equals await get data from backend. I found myself having to do the below to avoid undefined errors before we migrated to SvelteKit and using +page.ts load. So maybe I was using onMount improperly.
>> So there is a little bit of a gotcha with onMount. If you look at the reference documentations, svelte.dev/docs and look at the onMount area, it will tell you that you should not return a promise from onMount.

[00:02:09]
And any time you have an async function, that function will return a promise. It's just how async functions work. And the reason for that is that we need to get a reference to the teardown callback for when the component is unmounted, and that needs to happen synchronously for a variety of reasons.

[00:02:28]
So your onMount callbacks should be synchronous functions, they should not be async functions. You can use async inside an onMount function by creating, I believe it's called a synchronous immediately invoked function expression or IIFE. So you create an async function, and then you put the parentheses at the end of it, so it will call it.

[00:02:51]
And you can use the await keyword inside your IIFE, but you don't want the onMount callback itself to be an async function. Maybe we'll change that in a future version of Svelte, I don't know, but for now, avoid that per the documentation.
>> How does onMount impact the performance when the components have a waterfall effect or some sort?

[00:03:16]
>> Yes, so if you're doing your asynchronous work inside onMount, by which I mean like fetching data and things like that, then that work doesn't begin until the component gets mounted to the screen. And if you have a component that only becomes visible when the result of some async operation completes inside onMount, then if it has its own async operations.

[00:03:42]
Then you'll render the parent component that will eventually render the child component, which will do amazing work. Maybe that eventually renders another child component, and that is what we call a waterfall, and that is something that we very much want to avoid. In general, I do not recommend doing data fetching inside your onMount components.

[00:03:58]
There is a way of doing data fetching asynchronously, which we'll learn about in SvelteKit, and that is by far the preferred way to deal with data. Not just because it avoids that waterfall problem, but also because it works with server-side rendering. Server-side rendering does not work with onMount because there is no DOM on the server, you're not mounting anything.

[00:04:21]
So when you do work inside an onMount handler, that will have no effect on any content that you're server rendering. SSR is a thing that we're gonna cover in this SvelteKit workshop. For now, the takeaway is avoid doing your data fetching in onMount if you can and come back for the SvelteKit workshop to learn about data fetching.

[00:04:43]
>> If you have lots of await blocks in your HTML, would there be a better way to organize this? Also, is there a way to do something like promise.all for multiple await blocks?
>> So if you have a promise.all, you would put that inside, I mean, you can have an inline promise.all inside an await function.

[00:05:00]
But you probably want to do any really tricky async logic inside your script block or even in an external module, because as the question suggests, it can start to get a little bit hairy. But this again is the kind of stuff that is better moved into your data fetching layer, which happens before rendering, and that's something that we'll talk about when we learn SvelteKit.

[00:05:23]
>> Several people in chat are not sure what the tick does, and what does it do? [LAUGH]
>> [LAUGH] Okay, so the nuts and bolts of what tick does is, all right, so when you assign to a value in a component, the compiler instruments that assignment with a secret internal function called invalidate.

[00:05:51]
And invalidate has two jobs. It marks that value as dirty inside the component, and it tells a scheduler that is shared by all components that this component has changed. And when that happens, the batching starts. So Svelte will create a promise that will immediately resolve, and then it will wait to see if any other state updates happen before that promise resolves in the next microtask.

[00:06:23]
If you call tick, you will get a reference to that promise. So at the end of that resolution, the DOM will be updated and the promise returned from your tick function will resolve. If most state updates were happening, then it will just be like calling await promise.resolve. And it will essentially just defer some work until the next microtask.

[00:06:50]
Again, super in the weeds. Most of the time, you don't really need to worry about how it's working. You just need to know that it's gonna cause anything after the await tick to happen in the next microtask. Which is a fancy way of saying it will happen after the current execution block has happened, but before the DOM is updated.

[00:07:16]
So you're not gonna see things like flicker. It's not like if you're doing a setTimeout or something, and then you potentially see things in the page become out of sync. Everything will happen before the DOM is updated, but after the current execution block. Hopefully that makes sense.

[00:07:29]
>> What does this dot refer to?
>> It's a great question. Okay, so down here, we have this.selectionStart = selectionEnd, this.selectionEnd = selectionEnd. The this inside an event handler refers to the element that the event handler is bound to. So here, we're calling on:keydown=handleKeydown. Function blah, const textarea = event.currentTarget.

[00:08:10]
And hopefully, this is gonna work. If I press a key here, then we're gonna see this alert(this === textarea) alert were true. It worked, okay, good. I have remembered how the DOM works. Anytime you have an event handler, "this" is the event target. Just a convenient way to interact with the DOM imperatively.

[00:08:37]
Chris, you had a question?
>> Yeah, going back to the use of tick and how that's used to help resolve promises, is it possible then that you would have to call await tick multiple times in the same code block?
>> You should not need to, no. Now I can't really imagine a situation in which you'd wanna do that, unless you needed to do something like you change some state, and then you wait for the DOM to update.

[00:09:02]
So that maybe you can take a measurement like a width and a height measurement of an element so that you can then set some more state, and then that has a knock on effect that you need to await. I guess it's possible to get into a situation where that's the case, but it's not something that you would encounter often is what I mean.

[00:09:22]
All right, any more questions from the Internet, or should we move on to the final section of part one?
>> Just a couple of clarifications, so. So basically, a tick is like useEffect or useLayoutEffect in React. Yeah, I guess, so useLayoutEffect is where you declare a function that is gonna happen every time the dependencies of that effect change.

[00:09:53]
When you call tick, it's happening in some code that is already running, and it will only happen once, of course. But you would use it in much the same context as you would use useLayoutEffect, which is to take some measurement of the DOM or to do something in response to the DOM updating.

[00:10:14]
Whereas useEffect, you don't have the same guarantees about the callback getting executed immediately after the DOM has been updated. They reserve the right to do that after a period of time.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now