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';
22
22
import { queue_micro_task } from '../task.js' ;
23
23
import * as e from '../../errors.js' ;
24
24
import { DEV } from 'esm-env' ;
25
- import { Batch } from '../../reactivity/batch.js' ;
25
+ import { Batch , effect_pending_updates } from '../../reactivity/batch.js' ;
26
26
import { internal_set , source } from '../../reactivity/sources.js' ;
27
27
import { tag } from '../../dev/tracing.js' ;
28
28
import { createSubscriber } from '../../../../reactivity/create-subscriber.js' ;
@@ -92,6 +92,12 @@ export class Boundary {
92
92
*/
93
93
#effect_pending = null ;
94
94
95
+ #effect_pending_update = ( ) => {
96
+ if ( this . #effect_pending) {
97
+ internal_set ( this . #effect_pending, this . #pending_count) ;
98
+ }
99
+ } ;
100
+
95
101
#effect_pending_subscriber = createSubscriber ( ( ) => {
96
102
this . #effect_pending = source ( this . #pending_count) ;
97
103
@@ -238,11 +244,7 @@ export class Boundary {
238
244
this . parent . #update_pending_count( d ) ;
239
245
}
240
246
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) ;
246
248
}
247
249
248
250
get_effect_pending ( ) {
Original file line number Diff line number Diff line change @@ -49,6 +49,9 @@ export let batch_deriveds = null;
49
49
/** @type {Effect[] } Stack of effects, dev only */
50
50
export let dev_effect_stack = [ ] ;
51
51
52
+ /** @type {Set<() => void> } */
53
+ export let effect_pending_updates = new Set ( ) ;
54
+
52
55
/** @type {Effect[] } */
53
56
let queued_root_effects = [ ] ;
54
57
@@ -296,6 +299,16 @@ export class Batch {
296
299
297
300
deactivate ( ) {
298
301
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
+ }
299
312
}
300
313
301
314
neuter ( ) {
@@ -319,7 +332,7 @@ export class Batch {
319
332
batches . delete ( this ) ;
320
333
}
321
334
322
- current_batch = null ;
335
+ this . deactivate ( ) ;
323
336
}
324
337
325
338
flush_effects ( ) {
@@ -389,6 +402,8 @@ export class Batch {
389
402
this . #effects = [ ] ;
390
403
391
404
this . flush ( ) ;
405
+ } else {
406
+ this . deactivate ( ) ;
392
407
}
393
408
}
394
409
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