diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js index dfc5ac46fb..9b6c807067 100644 --- a/packages/svelte/src/internal/client/dom/blocks/boundary.js +++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js @@ -416,17 +416,6 @@ export function capture(track = true) { }; } -// TODO we should probably be incrementing the current batch, not the boundary? -export function suspend() { - let boundary = get_pending_boundary(); - - boundary.update_pending_count(1); - - return function unsuspend() { - boundary.update_pending_count(-1); - }; -} - /** * Wraps an `await` expression in such a way that the effect context that was * active before the expression evaluated can be reapplied afterwards — diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index bfbdefd095..25ef788604 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -98,6 +98,7 @@ export { props_id, with_script } from './dom/template.js'; +export { suspend } from './reactivity/batch.js'; export { async_derived, user_derived as derived, @@ -135,7 +136,7 @@ export { update_store, mark_store_binding } from './reactivity/store.js'; -export { boundary, pending, save, suspend } from './dom/blocks/boundary.js'; +export { boundary, pending, save } from './dom/blocks/boundary.js'; export { set_text } from './render.js'; export { get, diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 67d8e0a7ad..c64f3ab98c 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -1,6 +1,7 @@ /** @import { Derived, Effect, Source } from '#client' */ import { CLEAN, DIRTY } from '#client/constants'; import { deferred } from '../../shared/utils.js'; +import { get_pending_boundary } from '../dom/blocks/boundary.js'; import { flush_queued_effects, flush_queued_root_effects, @@ -275,6 +276,8 @@ export class Batch { this.render_effects = []; this.effects = []; + + this.flush(); } } @@ -322,6 +325,20 @@ export class Batch { } } +export function suspend() { + var boundary = get_pending_boundary(); + var batch = /** @type {Batch} */ (current_batch); + var pending = boundary.pending; + + boundary.update_pending_count(1); + if (!pending) batch.increment(); + + return function unsuspend() { + boundary.update_pending_count(-1); + if (!pending) batch.decrement(); + }; +} + /** * Forcibly remove all current batches, to prevent cross-talk between tests */ diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 05f34bebc9..ef72751a85 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -152,11 +152,6 @@ export function async_derived(fn, location) { from_async_derived = null; - if (should_suspend) { - boundary.update_pending_count(-1); - if (!pending) batch.decrement(); - } - if (!pending) batch.restore(); if (error) { @@ -185,7 +180,10 @@ export function async_derived(fn, location) { } } - if (!pending) batch.flush(); + if (should_suspend) { + boundary.update_pending_count(-1); + if (!pending) batch.decrement(); + } }; promise.then(handler, (e) => handler(null, e || 'unknown')); diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/Child.svelte new file mode 100644 index 0000000000..7ad618f130 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/Child.svelte @@ -0,0 +1,7 @@ + + +

{value}

diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/_config.js b/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/_config.js new file mode 100644 index 0000000000..73c9b50a69 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/_config.js @@ -0,0 +1,40 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [toggle, hello] = target.querySelectorAll('button'); + + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + + toggle.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + + hello.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

condition is true

+

hello

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/main.svelte new file mode 100644 index 0000000000..d111ce6fe3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-in-if/main.svelte @@ -0,0 +1,20 @@ + + + + + + + {#if condition} +

condition is {condition}

+ + {/if} + + {#snippet pending()} +

pending

+ {/snippet} +