Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/long-roses-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: allow await expressions inside `{#await ...}` argument
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @import { BlockStatement, Pattern, Statement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */
import { extract_identifiers } from '../../../../utils/ast.js';
import { extract_identifiers, is_expression_async } from '../../../../utils/ast.js';
import * as b from '#compiler/builders';
import { create_derived } from '../utils.js';
import { get_value } from './shared/declarations.js';
Expand All @@ -15,7 +15,11 @@ export function AwaitBlock(node, context) {
context.state.template.push_comment();

// Visit {#await <expression>} first to ensure that scopes are in the correct order
const expression = b.thunk(build_expression(context, node.expression, node.metadata.expression));
const unthunked = build_expression(context, node.expression, node.metadata.expression);
const expression = b.thunk(
unthunked,
context.state.options.experimental.async && is_expression_async(unthunked)
);

let then_block;
let catch_block;
Expand Down
43 changes: 43 additions & 0 deletions packages/svelte/tests/runtime-runes/samples/async-await/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { tick } from 'svelte';
import { test } from '../../test';

export default test({
async test({ assert, target }) {
const [reset, one, two, reject] = target.querySelectorAll('button');

await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> waiting'
);

one.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> one_res'
);

reset.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> waiting'
);

two.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> two_res'
);

reset.click();
reject.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>reset</button><button>one</button><button>two</button><button>reject</button> reject_catch'
);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script>
let deferred = $state(Promise.withResolvers());
</script>

<button onclick={() => deferred = Promise.withResolvers()}>reset</button>
<button onclick={() => deferred.resolve("one")}>one</button>
<button onclick={() => deferred.resolve("two")}>two</button>
<button onclick={() => deferred.reject("reject")}>reject</button>

<svelte:boundary>
{#await await deferred.promise + "_res"}
waiting
{:then res}
{res}
{:catch err}
{err}_catch
{/await}

{#snippet pending()}
<p>pending</p>
{/snippet}
</svelte:boundary>
Loading