From 6b1ac77c87dfea0ca6bb32f3298f0abc7fea91a4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 3 Jul 2025 17:06:24 -0400 Subject: [PATCH] only update `$effect.pending()` if someone is listening, since it causes a double flush and makes debugging harder --- .../internal/client/dom/blocks/boundary.js | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js index d174dbdc5d..e6dbc2a7d1 100644 --- a/packages/svelte/src/internal/client/dom/blocks/boundary.js +++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js @@ -1,5 +1,4 @@ -/** @import { Effect, TemplateNode, } from '#client' */ - +/** @import { Effect, Source, TemplateNode, } from '#client' */ import { BOUNDARY_EFFECT, EFFECT_PRESERVED, EFFECT_TRANSPARENT } from '#client/constants'; import { component_context, set_component_context } from '../../context.js'; import { invoke_error_boundary } from '../../error-handling.js'; @@ -25,8 +24,9 @@ import * as e from '../../../shared/errors.js'; import { DEV } from 'esm-env'; import { from_async_derived, set_from_async_derived } from '../../reactivity/deriveds.js'; import { Batch } from '../../reactivity/batch.js'; -import { source, update } from '../../reactivity/sources.js'; +import { internal_set, source } from '../../reactivity/sources.js'; import { tag } from '../../dev/tracing.js'; +import { createSubscriber } from '../../../../reactivity/create-subscriber.js'; /** * @typedef {{ @@ -85,7 +85,22 @@ export class Boundary { #pending_count = 0; #is_creating_fallback = false; - effect_pending = source(0); + /** + * @type {Source | null} + */ + #effect_pending = null; + + #effect_pending_subscriber = createSubscriber(() => { + this.#effect_pending = source(this.#pending_count); + + if (DEV) { + tag(this.#effect_pending, '$effect.pending()'); + } + + return () => { + this.#effect_pending = null; + }; + }); /** * @param {TemplateNode} node @@ -103,10 +118,6 @@ export class Boundary { this.pending = !!this.#props.pending; - if (DEV) { - tag(this.effect_pending, '$effect.pending()'); - } - this.#effect = block(() => { /** @type {Effect} */ (active_effect).b = this; @@ -237,10 +248,17 @@ export class Boundary { } queueMicrotask(() => { - update(this.effect_pending, d); + if (this.#effect_pending) { + internal_set(this.#effect_pending, this.#pending_count); + } }); } + get_effect_pending() { + this.#effect_pending_subscriber(); + return get(/** @type {Source} */ (this.#effect_pending)); + } + /** @param {unknown} error */ error(error) { var onerror = this.#props.onerror; @@ -429,5 +447,5 @@ export function pending() { return 0; // TODO eventually we will need this to be global } - return get(boundary.effect_pending); + return boundary.get_effect_pending(); }