From 74b7f89679ca40ce1c07ae82c36807817fb4f7e4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 13 Jul 2025 22:08:09 -0400 Subject: [PATCH] move some code --- .../internal/client/dom/blocks/boundary.js | 63 -------------- packages/svelte/src/internal/client/index.js | 3 +- .../src/internal/client/reactivity/async.js | 84 ++++++++++++++++++- 3 files changed, 82 insertions(+), 68 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js index b2ec72c529..f32aea9a57 100644 --- a/packages/svelte/src/internal/client/dom/blocks/boundary.js +++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js @@ -366,69 +366,6 @@ export function get_pending_boundary() { return boundary; } -/** - * Captures the current effect context so that we can restore it after - * some asynchronous work has happened if `track` is true (so that e.g. - * `await a + b` causes `b` to be registered as a dependency). - * - * If `track` is false, we just take a note of which async derived - * brought us here, so that we can emit a `async_reactivity_loss` - * warning when it's appropriate to do so. - * - * @param {boolean} track - */ -export function capture(track = true) { - var previous_effect = active_effect; - var previous_reaction = active_reaction; - var previous_component_context = component_context; - - if (DEV && !track) { - var previous_async_effect = current_async_effect; - } - - return function restore() { - if (track) { - set_active_effect(previous_effect); - set_active_reaction(previous_reaction); - set_component_context(previous_component_context); - } - - if (DEV) { - set_from_async_derived(track ? null : previous_async_effect); - } - - // prevent the active effect from outstaying its welcome - // TODO this feels brittle - queue_micro_task(exit); - }; -} - -/** - * Wraps an `await` expression in such a way that the effect context that was - * active before the expression evaluated can be reapplied afterwards — - * `await a + b` becomes `(await $.save(a))() + b` - * @template T - * @param {Promise} promise - * @param {boolean} [track] - * @returns {Promise<() => T>} - */ -export async function save(promise, track = true) { - var restore = capture(track); - var value = await promise; - - return () => { - restore(); - return value; - }; -} - -function exit() { - set_active_effect(null); - set_active_reaction(null); - set_component_context(null); - if (DEV) set_from_async_derived(null); -} - export function pending() { if (active_effect === null) { e.effect_pending_outside_reaction(); diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index 04bad60c76..7293675312 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -98,6 +98,7 @@ export { props_id, with_script } from './dom/template.js'; +export { save } from './reactivity/async.js'; export { flushSync as flush, suspend } from './reactivity/batch.js'; export { async_derived, @@ -136,7 +137,7 @@ export { update_store, mark_store_binding } from './reactivity/store.js'; -export { boundary, pending, save } from './dom/blocks/boundary.js'; +export { boundary, pending } from './dom/blocks/boundary.js'; export { set_text } from './render.js'; export { get, diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 7e067ff490..d79e93d38b 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -1,12 +1,25 @@ /** @import { Effect, Value } from '#client' */ import { DESTROYED } from '#client/constants'; -import { is_runes } from '../context.js'; -import { capture, get_pending_boundary } from '../dom/blocks/boundary.js'; +import { DEV } from 'esm-env'; +import { component_context, is_runes, set_component_context } from '../context.js'; +import { get_pending_boundary } from '../dom/blocks/boundary.js'; import { invoke_error_boundary } from '../error-handling.js'; -import { active_effect } from '../runtime.js'; +import { + active_effect, + active_reaction, + set_active_effect, + set_active_reaction +} from '../runtime.js'; import { current_batch } from './batch.js'; -import { async_derived, derived, derived_safe_equal } from './deriveds.js'; +import { + async_derived, + current_async_effect, + derived, + derived_safe_equal, + set_from_async_derived +} from './deriveds.js'; +import { queue_micro_task } from '../dom/task.js'; /** * @@ -49,3 +62,66 @@ export function flatten(sync, async, fn) { boundary.error(error); }); } + +/** + * Captures the current effect context so that we can restore it after + * some asynchronous work has happened if `track` is true (so that e.g. + * `await a + b` causes `b` to be registered as a dependency). + * + * If `track` is false, we just take a note of which async derived + * brought us here, so that we can emit a `async_reactivity_loss` + * warning when it's appropriate to do so. + * + * @param {boolean} track + */ +export function capture(track = true) { + var previous_effect = active_effect; + var previous_reaction = active_reaction; + var previous_component_context = component_context; + + if (DEV && !track) { + var previous_async_effect = current_async_effect; + } + + return function restore() { + if (track) { + set_active_effect(previous_effect); + set_active_reaction(previous_reaction); + set_component_context(previous_component_context); + } + + if (DEV) { + set_from_async_derived(track ? null : previous_async_effect); + } + + // prevent the active effect from outstaying its welcome + // TODO this feels brittle + queue_micro_task(exit); + }; +} + +/** + * Wraps an `await` expression in such a way that the effect context that was + * active before the expression evaluated can be reapplied afterwards — + * `await a + b` becomes `(await $.save(a))() + b` + * @template T + * @param {Promise} promise + * @param {boolean} [track] + * @returns {Promise<() => T>} + */ +export async function save(promise, track = true) { + var restore = capture(track); + var value = await promise; + + return () => { + restore(); + return value; + }; +} + +function exit() { + set_active_effect(null); + set_active_reaction(null); + set_component_context(null); + if (DEV) set_from_async_derived(null); +}