suspend batch, not boundary

pull/15844/head
Rich Harris 3 months ago
parent 3e1701024b
commit 983083fb82

@ -416,17 +416,6 @@ export function capture(track = true) {
}; };
} }
// TODO we should probably be incrementing the current batch, not the boundary?
export function suspend() {
let boundary = get_pending_boundary();
boundary.update_pending_count(1);
return function unsuspend() {
boundary.update_pending_count(-1);
};
}
/** /**
* Wraps an `await` expression in such a way that the effect context that was * Wraps an `await` expression in such a way that the effect context that was
* active before the expression evaluated can be reapplied afterwards * active before the expression evaluated can be reapplied afterwards

@ -98,6 +98,7 @@ export {
props_id, props_id,
with_script with_script
} from './dom/template.js'; } from './dom/template.js';
export { suspend } from './reactivity/batch.js';
export { export {
async_derived, async_derived,
user_derived as derived, user_derived as derived,
@ -135,7 +136,7 @@ export {
update_store, update_store,
mark_store_binding mark_store_binding
} from './reactivity/store.js'; } from './reactivity/store.js';
export { boundary, pending, save, suspend } from './dom/blocks/boundary.js'; export { boundary, pending, save } from './dom/blocks/boundary.js';
export { set_text } from './render.js'; export { set_text } from './render.js';
export { export {
get, get,

@ -1,6 +1,7 @@
/** @import { Derived, Effect, Source } from '#client' */ /** @import { Derived, Effect, Source } from '#client' */
import { CLEAN, DIRTY } from '#client/constants'; import { CLEAN, DIRTY } from '#client/constants';
import { deferred } from '../../shared/utils.js'; import { deferred } from '../../shared/utils.js';
import { get_pending_boundary } from '../dom/blocks/boundary.js';
import { import {
flush_queued_effects, flush_queued_effects,
flush_queued_root_effects, flush_queued_root_effects,
@ -275,6 +276,8 @@ export class Batch {
this.render_effects = []; this.render_effects = [];
this.effects = []; this.effects = [];
this.flush();
} }
} }
@ -322,6 +325,20 @@ export class Batch {
} }
} }
export function suspend() {
var boundary = get_pending_boundary();
var batch = /** @type {Batch} */ (current_batch);
var pending = boundary.pending;
boundary.update_pending_count(1);
if (!pending) batch.increment();
return function unsuspend() {
boundary.update_pending_count(-1);
if (!pending) batch.decrement();
};
}
/** /**
* Forcibly remove all current batches, to prevent cross-talk between tests * Forcibly remove all current batches, to prevent cross-talk between tests
*/ */

@ -152,11 +152,6 @@ export function async_derived(fn, location) {
from_async_derived = null; from_async_derived = null;
if (should_suspend) {
boundary.update_pending_count(-1);
if (!pending) batch.decrement();
}
if (!pending) batch.restore(); if (!pending) batch.restore();
if (error) { if (error) {
@ -185,7 +180,10 @@ export function async_derived(fn, location) {
} }
} }
if (!pending) batch.flush(); if (should_suspend) {
boundary.update_pending_count(-1);
if (!pending) batch.decrement();
}
}; };
promise.then(handler, (e) => handler(null, e || 'unknown')); promise.then(handler, (e) => handler(null, e || 'unknown'));

@ -0,0 +1,7 @@
<script>
let { promise } = $props();
let value = await promise;
</script>
<p>{value}</p>

@ -0,0 +1,40 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
const [toggle, hello] = target.querySelectorAll('button');
assert.htmlEqual(
target.innerHTML,
`
<button>toggle</button>
<button>hello</button>
`
);
toggle.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>toggle</button>
<button>hello</button>
`
);
hello.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>toggle</button>
<button>hello</button>
<p>condition is true</p>
<p>hello</p>
`
);
}
});

@ -0,0 +1,20 @@
<script>
import Child from './Child.svelte';
let condition = $state(false);
let deferred = $state(Promise.withResolvers());
</script>
<button onclick={() => condition = !condition}>toggle</button>
<button onclick={() => deferred.resolve('hello')}>hello</button>
<svelte:boundary>
{#if condition}
<p>condition is {condition}</p>
<Child promise={deferred.promise} />
{/if}
{#snippet pending()}
<p>pending</p>
{/snippet}
</svelte:boundary>
Loading…
Cancel
Save