Skip to main content

await

Svelte5.36 以降、コンポーネント内のうち、これまで使えなかった3箇所で await キーワードを使えるようになりました:

  • コンポーネントの <script> トップレベル
  • $derived(...) 宣言の内部
  • マークアップの内部

この機能は実験的なものであり、Svelteの設定(通常は svelte.config.js)に experimental.async オプションを追加して、明示的に有効にする必要があります:

svelte.config
export default {
	
compilerOptions: {
    experimental: {
        async: boolean;
    };
}
compilerOptions
: {
experimental: {
    async: boolean;
}
experimental
: {
async: booleanasync: true } } };

この実験的なフラグは Svelte 6 で削除される予定です。

同期された更新

ある await 式が特定の state に依存しているとき、その state への変更は、非同期処理が完了するまでUIに反映されません。UIが矛盾した状態にならないようにするためです。つまり、こちらのような例では...

<script>
	let a = $state(1);
	let b = $state(2);

	async function add(a, b) {
		await new Promise((f) => setTimeout(f, 500)); // artificial delay
		return a + b;
	}
</script>

<input type="number" bind:value={a}>
<input type="number" bind:value={b}>

<p>{a} + {b} = {await add(a, b)}</p>

...a の値をインクリメントしても、 <p> の内容は次のようには なりません。

<p>2 + 2 = 3</p>

実際には、add(a, b)が解決されたときに、<p>の内容を 2 + 2 = 4 に更新します。

更新は重複することがあります。先行する更新が遅く、まだ進行中であっても、続く更新が速ければ、速いほうが先にUIに反映されます。

並行性

Svelte は可能な限り非同期処理を並行におこないます。例えば、マークアップ内に2つの await 式があるとき...

<p>{await one()}</p>
<p>{await two()}</p>

...それらは独立した式ですので、 見た目上は 順次実行されているように見えても、両方の関数が同時に実行されます。

これは、<script> 内や非同期関数内の連続した await 式には適用されません。これらは他の非同期JavaScriptと同じように実行されます。例外として、独立した $derived 式は、最初の作成時には順次実行されますが、そのあとは独立して更新されます:

// これらは最初は順次実行されますが、
// そのあとは独立して更新されます
let let a: numbera = 
function $derived<number>(expression: number): number
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(await function one(): Promise<number>one());
let let b: numberb =
function $derived<number>(expression: number): number
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(await function two(): Promise<number>two());

このようなコードを書くと、Svelteから await_waterfall 警告が表示されます。

ローディング状態の表示

To render placeholder UI, you can wrap content in a <svelte:boundary> with a pending snippet. This will be shown when the boundary is first created, but not for subsequent updates, which are globally coordinated.

After the contents of a boundary have resolved for the first time and have replaced the pending snippet, you can detect subsequent async work with $effect.pending(). This is what you would use to display a “we’re asynchronously validating your input” spinner next to a form field, for example.

また、 settled() を使うと、現在の更新が完了したときに解決(resolve)される Promise を取得できます:

import { function tick(): Promise<void>

Returns a promise that resolves once any pending state changes have been applied.

tick
, function settled(): Promise<void>

Returns a promise that resolves once any state changes, and asynchronous work resulting from them, have resolved and the DOM has been updated

@since5.36
settled
} from 'svelte';
async function function onclick(): Promise<void>onclick() { let updating: booleanupdating = true; // これがないと、`updating` への変更は // 他の変更とまとめられてしまうため、 // UI に反映されません await function tick(): Promise<void>

Returns a promise that resolves once any pending state changes have been applied.

tick
();
let color: stringcolor = 'octarine'; let answer: numberanswer = 42; await function settled(): Promise<void>

Returns a promise that resolves once any state changes, and asynchronous work resulting from them, have resolved and the DOM has been updated

@since5.36
settled
();
// `color` や `answer` の変更に影響される // あらゆる更新が、この時点で適用済みになります let updating: booleanupdating = false; }

エラーハンドリング

await 式のエラーは、もっとも近い error boundary に伝播します。

Server-side rendering

Svelte supports asynchronous server-side rendering (SSR) with the render(...) API. To use it, simply await the return value:

server
import { 
function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
    props?: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
    props: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
}]): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
} from 'svelte/server';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte';
const { const head: string

HTML that goes into the &#x3C;head>

head
, const body: string

HTML that goes somewhere into the &#x3C;body>

body
} = await
render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
    ...;
} | undefined): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
(const App: LegacyComponentTypeApp);

If you’re using a framework like SvelteKit, this is done on your behalf.

If a <svelte:boundary> with a pending snippet is encountered during SSR, that snippet will be rendered while the rest of the content is ignored. All await expressions encountered outside boundaries with pending snippets will resolve and render their contents prior to await render(...) returning.

In the future, we plan to add a streaming implementation that renders the content in the background.

注意事項

実験的な機能であるため、 await 扱いの詳細(および $effect.pending() のような関連API)は、セマンティックバージョニングのメジャーリリース外では破壊的変更がおこなわれる可能性があります。ただし、そのような変更は最小限に抑えるつもりです。

破壊的変更

experimental.async オプションが true のとき、効果の実行順序がわずかに異なります。具体的には、 {#if ...}{#each ...} のような ブロック の効果を、 $effect.prebeforeUpdate の前に実行するようになります。これにより、非常にまれな状況では、存在しないはずのブロックを更新してしまう可能性があります。ただし、これは効果内で state を更新した場合に限られますし、そのような状況は避けるべきです

Edit this page on GitHub llms.txt

previous next