From 27dbad89979cb4eec20a29d0f10d6097067febe7 Mon Sep 17 00:00:00 2001 From: David Roizenman Date: Fri, 16 Jan 2026 15:51:13 -0800 Subject: [PATCH] skip settled blockers more aggressively --- .../src/internal/client/reactivity/async.js | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 000e9ca429..ad818f7965 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -44,6 +44,9 @@ export function is_promise_settled(promise) { export function flatten(blockers, sync, async, fn) { const d = is_runes() ? derived : derived_safe_equal; + // Filter out already-settled blockers - no need to wait for them + blockers = blockers.filter((b) => !is_promise_settled(b)); + if (async.length === 0 && blockers.length === 0) { fn(sync.map(d)); return; @@ -53,40 +56,41 @@ export function flatten(blockers, sync, async, fn) { var parent = /** @type {Effect} */ (active_effect); var restore = capture(); + var blocker_promise = + blockers.length === 1 ? blockers[0] : blockers.length > 1 ? Promise.all(blockers) : null; - function run() { - Promise.all(async.map((expression) => async_derived(expression))) - .then((result) => { - restore(); - - try { - fn([...sync.map(d), ...result]); - } catch (error) { - // ignore errors in blocks that have already been destroyed - if ((parent.f & DESTROYED) === 0) { - invoke_error_boundary(error, parent); - } - } + /** @param {Value[]} values */ + function finish(values) { + restore(); - batch?.deactivate(); - unset_context(); - }) - .catch((error) => { + try { + fn(values); + } catch (error) { + if ((parent.f & DESTROYED) === 0) { invoke_error_boundary(error, parent); - }); + } + } + + batch?.deactivate(); + unset_context(); } - if (blockers.length > 0) { - Promise.all(blockers).then(() => { - restore(); + // Fast path: blockers but no async expressions + if (async.length === 0) { + /** @type {Promise} */ (blocker_promise).then(() => finish(sync.map(d))); + return; + } - try { - return run(); - } finally { - batch?.deactivate(); - unset_context(); - } - }); + // Full path: has async expressions + function run() { + restore(); + Promise.all(async.map((expression) => async_derived(expression))) + .then((result) => finish([...sync.map(d), ...result])) + .catch((error) => invoke_error_boundary(error, parent)); + } + + if (blocker_promise) { + blocker_promise.then(run); } else { run(); }