Problem
Client islands that fetch JSON need local loading and error UI without hand
maintaining Loading and Error state fields around every async handler.
Before this feature, the markup parser rejected {#await} entirely, so island
authors had to spread async control flow across client state, handler code, and
conditional markup.
Goals
- Support a bounded
{#await}markup block inside JS client islands. - Render pending, resolved, and error branches around compiler-owned async fetches.
- Keep async execution deterministic and local to the island runtime.
- Preserve the bounded client language: no arbitrary Promise or raw JavaScript access from markup.
Non-Goals
- Supporting
g:awaitorg:asyncdirectives. - Supporting arbitrary JavaScript promises.
- Supporting value-returning async helper functions before the broader client return-type work lands.
Users And Permissions
- Primary users: GOWDK component authors building browser-enhanced islands.
- Roles or permissions: no special roles.
- Data visibility rules: fetched data is visible only to the client island that requested it.
User Flow
- The author writes
{#await fetchJSON[T](urlExpr)}in a component view. - The pending branch renders immediately.
- The runtime fetches JSON, swaps in the
{:then name}branch on success, or swaps in the{:catch err}branch on failure.
Requirements
Functional
- Parse
{#await expr},{:then name}, optional{:catch err}, and{/await}. - Validate that
exprisfetchJSON[T](urlExpr)and thaturlExpris a bounded client expression. - Expose the resolved value to the
thenbranch and an error object withmessageto thecatchbranch. - Re-run nested client conditionals, loops, bindings, and event handlers after a branch swap.
- Abort stale fetches when an await expression is replaced or the island is destroyed.
Non-Functional
- Performance: fetch and render only within the owning island.
- Reliability: stale async results must not replace newer branch state.
- Accessibility: authors control accessible pending/error markup.
- Security/privacy: only root-relative or otherwise compiler-validated URL
expressions already allowed by
fetchJSONmay be used. - Observability: fetches keep the existing island trace lane.
Acceptance Criteria
- Parser/model/render tests cover valid and invalid await blocks.
- Browser/runtime tests cover pending, success, error, and nested branch bindings.
- Docs describe the supported syntax and exclusions.
- Existing async handler behavior remains unchanged.
Edge Cases
- Missing
{:then}is rejected. - Duplicate
{:then}or{:catch}is rejected. - Await blocks outside component islands are rejected.
- Branch variables must be valid identifiers and must not collide with each other.
Dependencies
- Internal: view parser/model, view renderer, JS island runtime, client expression validator.
- External: browser
fetchandAbortControllerwhen available.
Open Questions
- Value-returning async helper functions should be handled with #501 rather than this bounded markup slice.