File tree Expand file tree Collapse file tree 5 files changed +142
-7
lines changed
tests/runtime-runes/samples/async-effect-pending Expand file tree Collapse file tree 5 files changed +142
-7
lines changed Original file line number Diff line number Diff line change 1+ ---
2+ ' svelte ' : patch
3+ ---
4+
5+ fix: update ` $effect.pending() ` immediately after a batch is removed
Original file line number Diff line number Diff line change @@ -22,7 +22,7 @@ import { get_next_sibling } from '../operations.js';
2222import { queue_micro_task } from '../task.js' ;
2323import * as e from '../../errors.js' ;
2424import { DEV } from 'esm-env' ;
25- import { Batch } from '../../reactivity/batch.js' ;
25+ import { Batch , effect_pending_updates } from '../../reactivity/batch.js' ;
2626import { internal_set , source } from '../../reactivity/sources.js' ;
2727import { tag } from '../../dev/tracing.js' ;
2828import { createSubscriber } from '../../../../reactivity/create-subscriber.js' ;
@@ -92,6 +92,12 @@ export class Boundary {
9292 */
9393 #effect_pending = null ;
9494
95+ #effect_pending_update = ( ) => {
96+ if ( this . #effect_pending) {
97+ internal_set ( this . #effect_pending, this . #pending_count) ;
98+ }
99+ } ;
100+
95101 #effect_pending_subscriber = createSubscriber ( ( ) => {
96102 this . #effect_pending = source ( this . #pending_count) ;
97103
@@ -238,11 +244,7 @@ export class Boundary {
238244 this . parent . #update_pending_count( d ) ;
239245 }
240246
241- queueMicrotask ( ( ) => {
242- if ( this . #effect_pending) {
243- internal_set ( this . #effect_pending, this . #pending_count) ;
244- }
245- } ) ;
247+ effect_pending_updates . add ( this . #effect_pending_update) ;
246248 }
247249
248250 get_effect_pending ( ) {
Original file line number Diff line number Diff line change @@ -49,6 +49,9 @@ export let batch_deriveds = null;
4949/** @type {Effect[] } Stack of effects, dev only */
5050export let dev_effect_stack = [ ] ;
5151
52+ /** @type {Set<() => void> } */
53+ export let effect_pending_updates = new Set ( ) ;
54+
5255/** @type {Effect[] } */
5356let queued_root_effects = [ ] ;
5457
@@ -296,6 +299,16 @@ export class Batch {
296299
297300 deactivate ( ) {
298301 current_batch = null ;
302+
303+ for ( const update of effect_pending_updates ) {
304+ effect_pending_updates . delete ( update ) ;
305+ update ( ) ;
306+
307+ if ( current_batch !== null ) {
308+ // only do one at a time
309+ break ;
310+ }
311+ }
299312 }
300313
301314 neuter ( ) {
@@ -319,7 +332,7 @@ export class Batch {
319332 batches . delete ( this ) ;
320333 }
321334
322- current_batch = null ;
335+ this . deactivate ( ) ;
323336 }
324337
325338 flush_effects ( ) {
@@ -389,6 +402,8 @@ export class Batch {
389402 this . #effects = [ ] ;
390403
391404 this . flush ( ) ;
405+ } else {
406+ this . deactivate ( ) ;
392407 }
393408 }
394409
Original file line number Diff line number Diff line change 1+ import { tick } from 'svelte' ;
2+ import { test } from '../../test' ;
3+
4+ export default test ( {
5+ async test ( { assert, target } ) {
6+ const [ increment , shift ] = target . querySelectorAll ( 'button' ) ;
7+
8+ shift . click ( ) ;
9+ shift . click ( ) ;
10+ shift . click ( ) ;
11+
12+ await tick ( ) ;
13+ assert . htmlEqual (
14+ target . innerHTML ,
15+ `
16+ <button>increment</button>
17+ <button>shift</button>
18+ <p>0</p>
19+ <p>0</p>
20+ <p>0</p>
21+ <p>pending: 0</p>
22+ `
23+ ) ;
24+
25+ increment . click ( ) ;
26+ await tick ( ) ;
27+ assert . htmlEqual (
28+ target . innerHTML ,
29+ `
30+ <button>increment</button>
31+ <button>shift</button>
32+ <p>0</p>
33+ <p>0</p>
34+ <p>0</p>
35+ <p>pending: 3</p>
36+ `
37+ ) ;
38+
39+ shift . click ( ) ;
40+ await tick ( ) ;
41+ assert . htmlEqual (
42+ target . innerHTML ,
43+ `
44+ <button>increment</button>
45+ <button>shift</button>
46+ <p>0</p>
47+ <p>0</p>
48+ <p>0</p>
49+ <p>pending: 2</p>
50+ `
51+ ) ;
52+
53+ shift . click ( ) ;
54+ await tick ( ) ;
55+ assert . htmlEqual (
56+ target . innerHTML ,
57+ `
58+ <button>increment</button>
59+ <button>shift</button>
60+ <p>0</p>
61+ <p>0</p>
62+ <p>0</p>
63+ <p>pending: 1</p>
64+ `
65+ ) ;
66+
67+ shift . click ( ) ;
68+ await tick ( ) ;
69+ assert . htmlEqual (
70+ target . innerHTML ,
71+ `
72+ <button>increment</button>
73+ <button>shift</button>
74+ <p>1</p>
75+ <p>1</p>
76+ <p>1</p>
77+ <p>pending: 0</p>
78+ `
79+ ) ;
80+ }
81+ } ) ;
Original file line number Diff line number Diff line change 1+ <script >
2+ let value = $state (0 );
3+ let deferreds = [];
4+
5+ function push (value ) {
6+ const deferred = Promise .withResolvers ();
7+ deferreds .push ({ value, deferred });
8+ return deferred .promise ;
9+ }
10+
11+ function shift () {
12+ const d = deferreds .shift ();
13+ d? .deferred .resolve (d .value );
14+ }
15+ < / script>
16+
17+ < button onclick= {() => value++ }> increment< / button>
18+ < button onclick= {() => shift ()}> shift< / button>
19+
20+ < svelte: boundary>
21+ < p> {await push (value)}< / p>
22+ < p> {await push (value)}< / p>
23+ < p> {await push (value)}< / p>
24+
25+ < p> pending: {$effect .pending ()}< / p>
26+
27+ {#snippet pending ()}
28+ < p> loading... < / p>
29+ {/ snippet}
30+ < / svelte: boundary>
31+
32+
You can’t perform that action at this time.
0 commit comments