From 3006fc71965afbfa2e19a5240a40aee5fbcc86b8 Mon Sep 17 00:00:00 2001 From: Paolo Ricciuti Date: Wed, 6 Nov 2024 18:51:09 +0100 Subject: [PATCH] fix: restore active reaction if then block throws (#14191) --- .changeset/pink-doors-chew.md | 5 ++ .../src/internal/client/dom/blocks/await.js | 64 ++++++++++--------- .../_config.js | 16 +++++ .../main.svelte | 21 ++++++ 4 files changed, 75 insertions(+), 31 deletions(-) create mode 100644 .changeset/pink-doors-chew.md create mode 100644 packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/main.svelte diff --git a/.changeset/pink-doors-chew.md b/.changeset/pink-doors-chew.md new file mode 100644 index 000000000000..ea43c5e00cd1 --- /dev/null +++ b/.changeset/pink-doors-chew.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: restore active reaction if then block throws diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index 3c6bc9900da8..29ef15452fdf 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -70,42 +70,44 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) { if (DEV) set_dev_current_component_function(component_function); } - if (state === PENDING && pending_fn) { - if (pending_effect) resume_effect(pending_effect); - else pending_effect = branch(() => pending_fn(anchor)); - } - - if (state === THEN && then_fn) { - if (then_effect) resume_effect(then_effect); - else then_effect = branch(() => then_fn(anchor, input_source)); - } + try { + if (state === PENDING && pending_fn) { + if (pending_effect) resume_effect(pending_effect); + else pending_effect = branch(() => pending_fn(anchor)); + } - if (state === CATCH && catch_fn) { - if (catch_effect) resume_effect(catch_effect); - else catch_effect = branch(() => catch_fn(anchor, error_source)); - } + if (state === THEN && then_fn) { + if (then_effect) resume_effect(then_effect); + else then_effect = branch(() => then_fn(anchor, input_source)); + } - if (state !== PENDING && pending_effect) { - pause_effect(pending_effect, () => (pending_effect = null)); - } + if (state === CATCH && catch_fn) { + if (catch_effect) resume_effect(catch_effect); + else catch_effect = branch(() => catch_fn(anchor, error_source)); + } - if (state !== THEN && then_effect) { - pause_effect(then_effect, () => (then_effect = null)); - } + if (state !== PENDING && pending_effect) { + pause_effect(pending_effect, () => (pending_effect = null)); + } - if (state !== CATCH && catch_effect) { - pause_effect(catch_effect, () => (catch_effect = null)); - } + if (state !== THEN && then_effect) { + pause_effect(then_effect, () => (then_effect = null)); + } - if (restore) { - if (DEV) set_dev_current_component_function(null); - set_component_context(null); - set_active_reaction(null); - set_active_effect(null); - - // without this, the DOM does not update until two ticks after the promise - // resolves, which is unexpected behaviour (and somewhat irksome to test) - flush_sync(); + if (state !== CATCH && catch_effect) { + pause_effect(catch_effect, () => (catch_effect = null)); + } + } finally { + if (restore) { + if (DEV) set_dev_current_component_function(null); + set_component_context(null); + set_active_reaction(null); + set_active_effect(null); + + // without this, the DOM does not update until two ticks after the promise + // resolves, which is unexpected behaviour (and somewhat irksome to test) + flush_sync(); + } } } diff --git a/packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/_config.js b/packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/_config.js new file mode 100644 index 000000000000..5cae253851a0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/_config.js @@ -0,0 +1,16 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + compileOptions: { + dev: true + }, + async test({ target, errors, assert, window }) { + const btn = target.querySelector('button'); + ok(btn); + flushSync(() => { + btn.click(); + }); + assert.deepEqual(errors, []); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/main.svelte b/packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/main.svelte new file mode 100644 index 000000000000..4e9e32dcabf9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/await-render-error-restore-reaction/main.svelte @@ -0,0 +1,21 @@ + + + + +{#await Promise.resolve() then} + {err.or} +{/await} \ No newline at end of file