From e1e04d0315e62e6b73dda4a624549d7e4b93460d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 13 Oct 2025 16:23:07 -0400 Subject: [PATCH] fix: unset context on stale promises (slightly different approach) (#16936) * slightly different approach to #16935 * move unset_context call --- .../internal/client/reactivity/deriveds.js | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 8a1f4666ec..076a919236 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -113,32 +113,24 @@ export function async_derived(fn, location) { // only suspend in async deriveds created on initialisation var should_suspend = !active_reaction; - /** @type {Map> & { rejected?: boolean }>} */ + /** @type {Map>>} */ var deferreds = new Map(); async_effect(() => { if (DEV) current_async_effect = active_effect; - /** @type {ReturnType> & { rejected?: boolean }} */ + /** @type {ReturnType>} */ var d = deferred(); promise = d.promise; try { // If this code is changed at some point, make sure to still access the then property // of fn() to read any signals it might access, so that we track them as dependencies. - Promise.resolve(fn()).then((v) => { - if (d.rejected) { - // If we rejected this stale promise, d.resolve - // is a noop (d.promise.then(handler) below will never run). - // In this case we need to unset the restored context here - // to avoid leaking it (and e.g. cause false-positive mutation errors). - unset_context(); - } else { - d.resolve(v); - } - }, d.reject); + // We call `unset_context` to undo any `save` calls that happen inside `fn()` + Promise.resolve(fn()).then(d.resolve, d.reject).then(unset_context); } catch (error) { d.reject(error); + unset_context(); } if (DEV) current_async_effect = null; @@ -151,11 +143,7 @@ export function async_derived(fn, location) { if (!pending) { batch.increment(); - var previous_deferred = deferreds.get(batch); - if (previous_deferred) { - previous_deferred.rejected = true; - previous_deferred.reject(STALE_REACTION); - } + deferreds.get(batch)?.reject(STALE_REACTION); deferreds.set(batch, d); } } @@ -199,8 +187,6 @@ export function async_derived(fn, location) { boundary.update_pending_count(-1); if (!pending) batch.decrement(); } - - unset_context(); }; d.promise.then(handler, (e) => handler(null, e || 'unknown'));