diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js index 4254c5d82d..e7141e06a8 100644 --- a/packages/svelte/src/internal/client/dom/blocks/boundary.js +++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js @@ -1,6 +1,6 @@ /** @import { Effect, TemplateNode, } from '#client' */ -import { BOUNDARY_EFFECT, EFFECT_PRESERVED, EFFECT_TRANSPARENT } from '#client/constants'; +import { BOUNDARY_EFFECT, EFFECT_PRESERVED, EFFECT_TRANSPARENT, INERT } from '#client/constants'; import { component_context, set_component_context } from '../../context.js'; import { invoke_error_boundary } from '../../error-handling.js'; import { block, branch, destroy_effect, pause_effect } from '../../reactivity/effects.js'; @@ -151,6 +151,14 @@ export class Boundary { return !!this.#props.pending; } + is_pending() { + if (!this.ran && this.#props.pending) { + return true; + } + + return this.#pending_effect !== null && (this.#pending_effect.f & INERT) === 0; + } + /** * @param {() => Effect | null} fn */ diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 13dc64026f..d48d225a56 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -51,6 +51,9 @@ export class Batch { /** @type {Effect[]} */ async_effects = []; + /** @type {Effect[]} */ + boundary_async_effects = []; + /** @type {Effect[]} */ render_effects = []; @@ -188,7 +191,12 @@ export class Batch { update_effect(effect); } + for (const effect of this.boundary_async_effects) { + update_effect(effect); + } + this.async_effects = []; + this.boundary_async_effects = []; } /** diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index d6a73b8e36..c0f55c2614 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -132,7 +132,7 @@ export function async_derived(fn, location) { prev = promise; var batch = /** @type {Batch} */ (current_batch); - var ran = boundary.ran; + var ran = !boundary.is_pending(); if (should_suspend) { (ran ? batch : boundary).increment(); diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 8c1d706fa5..d3303704bc 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -654,8 +654,11 @@ export function process_effects(batch, root) { if (!skip && effect.fn !== null) { if ((flags & EFFECT_ASYNC) !== 0) { + const boundary = effect.b; + if (check_dirtiness(effect)) { - batch.async_effects.push(effect); + var effects = boundary?.is_pending() ? batch.boundary_async_effects : batch.async_effects; + effects.push(effect); } } else if ((flags & BLOCK_EFFECT) !== 0) { if (check_dirtiness(effect)) { diff --git a/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js b/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js index 1405ee6e9f..560a239790 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-abort-signal/_config.js @@ -1,4 +1,4 @@ -import { flushSync, tick } from 'svelte'; +import { settled } from 'svelte'; import { test } from '../../test'; export default test({ @@ -9,22 +9,17 @@ export default test({ const [reset, resolve] = target.querySelectorAll('button'); - flushSync(() => reset.click()); - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); - await tick(); + reset.click(); + await settled(); assert.deepEqual(logs, ['aborted']); - flushSync(() => resolve.click()); + resolve.click(); + await Promise.resolve(); + await Promise.resolve(); await Promise.resolve(); await Promise.resolve(); await Promise.resolve(); await Promise.resolve(); - await tick(); assert.htmlEqual( target.innerHTML, `