From 179f66b297a1cfd943ad31dcd575587d629c412c Mon Sep 17 00:00:00 2001 From: jarrednorris <58517737+jarrednorrisdev@users.noreply.github.com> Date: Tue, 6 Oct 2026 10:50:59 +0100 Subject: [PATCH] fix: don't create async deriveds for a component destroyed while waiting for its top-level `await` (#18931) Fixes #18930 --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- .changeset/brave-owls-wait.md | 5 +++ .../src/internal/client/reactivity/async.js | 5 +++ .../Child.svelte | 7 +++++ .../_config.js | 31 +++++++++++++++++++ .../main.svelte | 20 ++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 .changeset/brave-owls-wait.md create mode 100644 packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/main.svelte diff --git a/.changeset/brave-owls-wait.md b/.changeset/brave-owls-wait.md new file mode 100644 index 0000000000..827868b8c3 --- /dev/null +++ b/.changeset/brave-owls-wait.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: don't create async deriveds for a component destroyed while waiting for its top-level `await` diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index a75f97a54f..efdfe6625c 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -103,6 +103,11 @@ export function flatten(blockers, sync, async, fn) { if (blocker_promise) { blocker_promise.then(() => { + if ((parent.f & DESTROYED) !== 0) { + decrement_pending(); + return; + } + restore(); run(); unset_context(); diff --git a/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/Child.svelte new file mode 100644 index 0000000000..63a16dde43 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/Child.svelte @@ -0,0 +1,7 @@ + + +
{await Promise.resolve(value)}
diff --git a/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/_config.js b/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/_config.js new file mode 100644 index 0000000000..096f90e2df --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/_config.js @@ -0,0 +1,31 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [hide, resolve] = target.querySelectorAll('button'); + + assert.htmlEqual( + target.innerHTML, + ` + + +loading...
+ ` + ); + + hide.click(); + await tick(); + + resolve.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/main.svelte new file mode 100644 index 0000000000..3bc50e5d24 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-destroyed-before-blockers-settle/main.svelte @@ -0,0 +1,20 @@ + + + + + +loading...
+ {/snippet} +