This is the PR to go with https://github.com/sveltejs/svelte/discussions/15845. Feedback and questions should happen on the discussion rather than here. ## How this works I'll likely flesh this out in more detail later, but a few quick bullet points: - state changes are now scoped to a `Batch`. This was always implied (we would flush effects in a microtask, if a `flushSync` didn't get there first, so that `a++; b++` would result in one flush rather than two) but now it's explicit - `Batch` has a `process` method that is responsible for calling `process_effects`. Whereas previously this would result in effects running immediately (albeit in two phases, so that e.g. `$effect` effects happen after other updates), this now only happens for async effects (so that we can know if a state change resulted in async work) and block effects (so that we can know if a newly-created branch has async work, or if newly-destroyed branches can be skipped). All other effects (i.e. user effects, or those that update the DOM) are added to the batch - if, after flushing everything, the batch is 'settled', we run the remaining effects. Otherwise, those effects will be scheduled when the batch's async deriveds resolve - batches track the _previous_ values of their sources, so that changes can be momentarily reverted in the case of overlapping batches - blocks like `{#if ...}` etc no longer append or remove branches directly. Instead, they do that in a commit callback belonging to the batch, which runs when everything is settled - we introduce the concept of an _async derived_, which isn't actually a derived at all — it's a source and an async effect (which is just a normal effect with a flag that lets `process_effects` run it eagerly) in a trenchcoat. This is because deriveds are lazy and would never update in time - you create an async derived whenever you have a `$derived` with an `await` expression (that isn't inside a function), or whenever you have an `await` expression in a template effect - accordingly, `$.template_effect` now takes a third argument, which is an array of all async deriveds - control flow blocks (`{#if ...}` et al) can also contain `await` expressions, in which case they are wrapped in an `$.async` block. These simply pass the async derived to the inner logic, so that the blocks themselves don't need to be aware that they're dealing with async values I'm sure I'm overlooking a ton of stuff but that's as much braindump as I can give right now. Will add comments to more of the source code as and when I can. ## WIP This is not finished; there are bugs, and parts of the code are a little messy. Some stuff could possibly be extracted into a separate PR so that this one is smaller and more focused (e.g. converting boundaries to the `Boundary` class). --- ### Before submitting the PR, please make sure you do the following - [x] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs - [x] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`. - [x] This message body should clearly illustrate what problems it solves. - [x] Ideally, include a test that fails without this PR but passes with it. - [x] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`). ### Tests and linting - [x] Run the tests with `pnpm test` and lint the project with `pnpm lint`
This issue appears to be discussing a feature request or bug report related to the repository. Based on the content, it seems to be still under discussion. The issue was opened by Rich-Harris and has received 2 comments.