-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
fix: merge batches #16866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: merge batches #16866
Conversation
🦋 Changeset detectedLatest commit: a50d0ec The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
moving back to draft, some more improvements incoming |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks awesome. I'll wait for Simon to review as well before approving; I think everything is good but given he's more familiar with the clientside stuff he should definitely take a look
// TODO why is this necessary? why isn't `await tick()` enough? | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
await Promise.resolve(); | ||
flushSync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆 I saw this while I was working on async SSR and I was really hopeful we could murder it at some point
let is_earlier = true; | ||
|
||
for (const batch of batches) { | ||
if (batch === this) { | ||
is_earlier = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this concerns me - what was this logic supposed to do? Right now it's doing nothing because it's true before and after, and when I change this to is_earlier = false
tests start failing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, yeah i borked this up didn't i. updated to the following — basically, if I have three updates and all of them involve foo
, then if the second of the three resolves first I want to redo the first batch with the updated foo
value, but let the third batch keep its current, more recent value
for (const [source, value] of this.current) {
if (batch.current.has(source)) {
if (is_earlier) {
// bring the value up to date
batch.current.set(source, value);
} else {
// later batch has more recent value,
// no need to re-run these effects
continue;
}
}
mark_effects(source);
}
…to merge-batches
This is part of a project to update some of the async batching logic to handle a few edge cases that have cropped up.
The observable change here is that if you have an
await
expression that runs twice, and the second one somehow resolves before the first, they are no longer forced to resolve in linear order. The easiest way to see it is in this example — clicka++
thenb++
in quick succession:main
— the fastb++
update is blocked on the slowa++
updateb++
update occurs, followed by thea++
updateTo make this work, whenever a batch is committed, we essentially 'rebase' other pending batches on top of the newly applied state. In the example above, when we commit the fast
b++
update, we re-run any async effects that depend onb
in the context of the pendinga++
batch.Before submitting the PR, please make sure you do the following
feat:
,fix:
,chore:
, ordocs:
.packages/svelte/src
, add a changeset (npx changeset
).Tests and linting
pnpm test
and lint the project withpnpm lint