@@ -58,30 +58,7 @@ export class Boundary {
5858 /** @type {Boundary | null } */
5959 parent ;
6060
61- /**
62- * Whether this boundary is inside a boundary (including this one) that's showing a pending snippet.
63- * @type {boolean }
64- */
65- get pending ( ) {
66- if ( this . has_pending_snippet ( ) ) {
67- return this . #pending;
68- }
69-
70- // intentionally not throwing here, as the answer to "am I in a pending snippet" is false when
71- // there's no pending snippet at all
72- return this . parent ?. pending ?? false ;
73- }
74-
75- set pending ( value ) {
76- if ( this . has_pending_snippet ( ) ) {
77- this . #pending = value ;
78- } else if ( this . parent ) {
79- this . parent . pending = value ;
80- } else if ( value ) {
81- e . await_outside_boundary ( ) ;
82- }
83- // if we're trying to set it to `false` and yeeting that into the void, it's fine
84- }
61+ #pending = false ;
8562
8663 /** @type {TemplateNode } */
8764 #anchor;
@@ -110,28 +87,9 @@ export class Boundary {
11087 /** @type {DocumentFragment | null } */
11188 #offscreen_fragment = null ;
11289
113- /**
114- * Whether this boundary is inside a boundary (including this one) that's showing a pending snippet.
115- * Derived from {@link props.pending} and {@link cascading_pending_count}.
116- */
117- #pending = false ;
118-
119- /**
120- * The number of pending async deriveds/expressions within this boundary, not counting any parent or child boundaries.
121- * This controls `$effect.pending` for this boundary.
122- *
123- * Don't ever set this directly; use {@link update_pending_count} instead.
124- */
90+ #local_pending_count = 0 ;
12591 #pending_count = 0 ;
12692
127- /**
128- * Like {@link #pending_count}, but treats boundaries with no `pending` snippet as porous.
129- * This controls the pending snippet for this boundary.
130- *
131- * Don't ever set this directly; use {@link update_pending_count} instead.
132- */
133- #cascading_pending_count = 0 ;
134-
13593 #is_creating_fallback = false ;
13694 /** @type {boolean } */
13795 #server_rendered_pending = false ;
@@ -147,12 +105,12 @@ export class Boundary {
147105
148106 #effect_pending_update = ( ) => {
149107 if ( this . #effect_pending) {
150- internal_set ( this . #effect_pending, this . #pending_count ) ;
108+ internal_set ( this . #effect_pending, this . #local_pending_count ) ;
151109 }
152110 } ;
153111
154112 #effect_pending_subscriber = createSubscriber ( ( ) => {
155- this . #effect_pending = source ( this . #pending_count ) ;
113+ this . #effect_pending = source ( this . #local_pending_count ) ;
156114
157115 if ( DEV ) {
158116 tag ( this . #effect_pending, '$effect.pending()' ) ;
@@ -179,7 +137,7 @@ export class Boundary {
179137
180138 this . parent = /** @type {Effect } */ ( active_effect ) . b ;
181139
182- this . pending = ! ! this . #props. pending ;
140+ this . # pending = ! ! this . #props. pending ;
183141
184142 this . #effect = block ( ( ) => {
185143 /** @type {Effect } */ ( active_effect ) . b = this ;
@@ -201,10 +159,10 @@ export class Boundary {
201159 this . error ( error ) ;
202160 }
203161
204- if ( this . #cascading_pending_count > 0 ) {
162+ if ( this . #pending_count > 0 ) {
205163 this . #show_pending_snippet( ) ;
206164 } else {
207- this . pending = false ;
165+ this . # pending = false ;
208166 }
209167 }
210168 } , flags ) ;
@@ -235,7 +193,7 @@ export class Boundary {
235193
236194 // Since server rendered resolved content, we never show pending state
237195 // Even if client-side async operations are still running, the content is already displayed
238- this . pending = false ;
196+ this . # pending = false ;
239197 }
240198
241199 #hydrate_pending_content( ) {
@@ -255,7 +213,7 @@ export class Boundary {
255213 return branch ( ( ) => this . #children( this . #anchor) ) ;
256214 } ) ;
257215
258- if ( this . #cascading_pending_count > 0 ) {
216+ if ( this . #pending_count > 0 ) {
259217 this . #show_pending_snippet( ) ;
260218 } else {
261219 pause_effect ( /** @type {Effect } */ ( this . #pending_effect) , ( ) => {
@@ -267,6 +225,14 @@ export class Boundary {
267225 } ) ;
268226 }
269227
228+ /**
229+ * Returns `true` if the effect exists inside a boundary whose pending snippet is shown
230+ * @returns {boolean }
231+ */
232+ is_pending ( ) {
233+ return this . #pending || ( ! ! this . parent && this . parent . is_pending ( ) ) ;
234+ }
235+
270236 has_pending_snippet ( ) {
271237 return ! ! this . #props. pending ;
272238 }
@@ -308,12 +274,25 @@ export class Boundary {
308274 }
309275 }
310276
311- /** @param {number } d */
312- #update_cascading_pending_count( d ) {
313- this . #cascading_pending_count = Math . max ( this . #cascading_pending_count + d , 0 ) ;
277+ /**
278+ * Updates the pending count associated with the currently visible pending snippet,
279+ * if any, such that we can replace the snippet with content once work is done
280+ * @param {1 | -1 } d
281+ */
282+ #update_pending_count( d ) {
283+ if ( ! this . has_pending_snippet ( ) ) {
284+ if ( this . parent ) {
285+ this . parent . #update_pending_count( d ) ;
286+ return ;
287+ }
314288
315- if ( this . #cascading_pending_count === 0 ) {
316- this . pending = false ;
289+ e . await_outside_boundary ( ) ;
290+ }
291+
292+ this . #pending_count += d ;
293+
294+ if ( this . #pending_count === 0 ) {
295+ this . #pending = false ;
317296
318297 if ( this . #pending_effect) {
319298 pause_effect ( this . #pending_effect, ( ) => {
@@ -329,21 +308,15 @@ export class Boundary {
329308 }
330309
331310 /**
332- * @param {number } d
333- * @param {boolean } safe
334- * @param {boolean } first
311+ * Update the source that powers `$effect.pending()` inside this boundary,
312+ * and controls when the current `pending` snippet (if any) is removed.
313+ * Do not call from inside the class
314+ * @param {1 | -1 } d
335315 */
336- update_pending_count ( d , safe = false , first = true ) {
337- if ( first ) {
338- this . #pending_count = Math . max ( this . #pending_count + d , 0 ) ;
339- }
340-
341- if ( this . has_pending_snippet ( ) ) {
342- this . #update_cascading_pending_count( d ) ;
343- } else if ( this . parent ) {
344- this . parent . update_pending_count ( d , safe , false ) ;
345- }
316+ update_pending_count ( d ) {
317+ this . #update_pending_count( d ) ;
346318
319+ this . #local_pending_count += d ;
347320 effect_pending_updates . add ( this . #effect_pending_update) ;
348321 }
349322
@@ -396,9 +369,7 @@ export class Boundary {
396369 // If the failure happened while flushing effects, current_batch can be null
397370 Batch . ensure ( ) ;
398371
399- // this ensures we modify the cascading_pending_count of the correct parent
400- // by the number we're decreasing this boundary by
401- this . update_pending_count ( - this . #pending_count, true ) ;
372+ this . #local_pending_count = 0 ;
402373
403374 if ( this . #failed_effect !== null ) {
404375 pause_effect ( this . #failed_effect, ( ) => {
@@ -408,17 +379,17 @@ export class Boundary {
408379
409380 // we intentionally do not try to find the nearest pending boundary. If this boundary has one, we'll render it on reset
410381 // but it would be really weird to show the parent's boundary on a child reset.
411- this . pending = this . has_pending_snippet ( ) ;
382+ this . # pending = this . has_pending_snippet ( ) ;
412383
413384 this . #main_effect = this . #run( ( ) => {
414385 this . #is_creating_fallback = false ;
415386 return branch ( ( ) => this . #children( this . #anchor) ) ;
416387 } ) ;
417388
418- if ( this . #cascading_pending_count > 0 ) {
389+ if ( this . #pending_count > 0 ) {
419390 this . #show_pending_snippet( ) ;
420391 } else {
421- this . pending = false ;
392+ this . # pending = false ;
422393 }
423394 } ;
424395
0 commit comments