Skip to content

Commit ab32c96

Browse files
committed
Merge remote-tracking branch 'origin/main' into 1000-reading-derived-effects
2 parents cfd6446 + 6837246 commit ab32c96

File tree

2 files changed

+47
-43
lines changed
  • packages/svelte
    • src/internal/client/reactivity
    • tests/runtime-runes/samples/effect-order-7

2 files changed

+47
-43
lines changed

packages/svelte/src/internal/client/reactivity/batch.js

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,15 @@ export class Batch {
194194
// if we didn't start any new async work, and no async work
195195
// is outstanding from a previous flush, commit
196196
if (this.#async_effects.length === 0 && this.#pending === 0) {
197+
this.#commit();
198+
197199
var render_effects = this.#render_effects;
198200
var effects = this.#effects;
199201

200202
this.#render_effects = [];
201203
this.#effects = [];
202204
this.#block_effects = [];
203205

204-
this.#commit();
205-
206206
flush_queued_effects(render_effects);
207207
flush_queued_effects(effects);
208208

@@ -540,49 +540,49 @@ function flush_queued_effects(effects) {
540540
var length = effects.length;
541541
if (length === 0) return;
542542

543-
for (var i = 0; i < length; i++) {
544-
var effect = effects[i];
545-
546-
if ((effect.f & (DESTROYED | INERT)) === 0) {
547-
if (is_dirty(effect)) {
548-
var wv = write_version;
549-
550-
// updating a derived for also increase the write version but that doesn't mean
551-
// state was written to in the user effect...so we reset the derived writes
552-
// before running the effect so that we can subtract the amount of derived writes
553-
// from the write version when we detect if state was written to in the user effect
554-
reset_derived_writes();
555-
556-
update_effect(effect);
557-
558-
// Effects with no dependencies or teardown do not get added to the effect tree.
559-
// Deferred effects (e.g. `$effect(...)`) _are_ added to the tree because we
560-
// don't know if we need to keep them until they are executed. Doing the check
561-
// here (rather than in `update_effect`) allows us to skip the work for
562-
// immediate effects.
563-
if (effect.deps === null && effect.first === null && effect.nodes_start === null) {
564-
// if there's no teardown or abort controller we completely unlink
565-
// the effect from the graph
566-
if (effect.teardown === null && effect.ac === null) {
567-
// remove this effect from the graph
568-
unlink_effect(effect);
569-
} else {
570-
// keep the effect in the graph, but free up some memory
571-
effect.fn = null;
572-
}
573-
}
543+
var i = 0;
544+
545+
while (i < length) {
546+
var effect = effects[i++];
574547

575-
// if state is written in a user effect, abort and re-schedule, lest we run
576-
// effects that should be removed as a result of the state change
577-
if (write_version - get_derived_writes() > wv && (effect.f & USER_EFFECT) !== 0) {
578-
break;
548+
if ((effect.f & (DESTROYED | INERT)) === 0 && is_dirty(effect)) {
549+
var wv = write_version;
550+
551+
// updating a derived for also increase the write version but that doesn't mean
552+
// state was written to in the user effect...so we reset the derived writes
553+
// before running the effect so that we can subtract the amount of derived writes
554+
// from the write version when we detect if state was written to in the user effect
555+
reset_derived_writes();
556+
557+
update_effect(effect);
558+
559+
// Effects with no dependencies or teardown do not get added to the effect tree.
560+
// Deferred effects (e.g. `$effect(...)`) _are_ added to the tree because we
561+
// don't know if we need to keep them until they are executed. Doing the check
562+
// here (rather than in `update_effect`) allows us to skip the work for
563+
// immediate effects.
564+
if (effect.deps === null && effect.first === null && effect.nodes_start === null) {
565+
// if there's no teardown or abort controller we completely unlink
566+
// the effect from the graph
567+
if (effect.teardown === null && effect.ac === null) {
568+
// remove this effect from the graph
569+
unlink_effect(effect);
570+
} else {
571+
// keep the effect in the graph, but free up some memory
572+
effect.fn = null;
579573
}
580574
}
575+
576+
// if state is written in a user effect, abort and re-schedule, lest we run
577+
// effects that should be removed as a result of the state change
578+
if (write_version - get_derived_writes() > wv && (effect.f & USER_EFFECT) !== 0) {
579+
break;
580+
}
581581
}
582582
}
583583

584-
for (; i < length; i += 1) {
585-
schedule_effect(effects[i]);
584+
while (i < length) {
585+
schedule_effect(effects[i++]);
586586
}
587587
}
588588

packages/svelte/tests/runtime-runes/samples/effect-order-7/_config.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ import { flushSync } from 'svelte';
22
import { test } from '../../test';
33

44
export default test({
5-
skip: true,
5+
// For this to work in non-async mode, we would need to abort
6+
// inside `#traverse_effect_tree`, which would be very
7+
// complicated and annoying. Since this hasn't been
8+
// a real issue (AFAICT), we ignore it
9+
skip_no_async: true,
610

7-
async test({ assert, target, logs }) {
11+
async test({ target }) {
812
const [open, close] = target.querySelectorAll('button');
913

1014
flushSync(() => open.click());
11-
flushSync(() => close.click());
1215

13-
assert.deepEqual(logs, [true]);
16+
// if the effect queue isn't aborted after the state change, this will throw
17+
flushSync(() => close.click());
1418
}
1519
});

0 commit comments

Comments
 (0)