await
Svelte5.36 以降、コンポーネント内のうち、これまで使えなかった3箇所で await
キーワードを使えるようになりました:
- コンポーネントの
<script>
トップレベル $derived(...)
宣言の内部- マークアップの内部
この機能は実験的なものであり、Svelteの設定(通常は svelte.config.js
)に experimental.async
オプションを追加して、明示的に有効にする必要があります:
export default {
compilerOptions: {
experimental: {
async: boolean;
};
}
compilerOptions: {
experimental: {
async: boolean;
}
experimental: {
async: boolean
async: 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: number
a = 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);
$derived(await function one(): Promise<number>
one());
let let b: number
b = 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);
$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
settled } from 'svelte';
async function function onclick(): Promise<void>
onclick() {
let updating: boolean
updating = true;
// これがないと、`updating` への変更は
// 他の変更とまとめられてしまうため、
// UI に反映されません
await function tick(): Promise<void>
Returns a promise that resolves once any pending state changes have been applied.
tick();
let color: string
color = 'octarine';
let answer: number
answer = 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
settled();
// `color` や `answer` の変更に影響される
// あらゆる更新が、この時点で適用済みになります
let updating: boolean
updating = 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:
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 <head>
head, const body: string
HTML that goes somewhere into the <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: LegacyComponentType
App);
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.pre
や beforeUpdate
の前に実行するようになります。これにより、非常にまれな状況では、存在しないはずのブロックを更新してしまう可能性があります。ただし、これは効果内で state を更新した場合に限られますし、そのような状況は避けるべきです。
Edit this page on GitHub llms.txt