Skip to main content

await

从 Svelte 5.36 开始,你可以在组件内部的三个地方使用 await 关键字,而之前该关键字不可用:

¥As of Svelte 5.36, you can use the await keyword inside your components in three places where it was previously unavailable:

  • 在组件的 <script> 顶层

    ¥at the top level of your component’s <script>

  • $derived(...) 声明内

    ¥inside $derived(...) declarations

  • 在你的标记内

    ¥inside your markup

此功能目前处于实验阶段,你必须在 Svelte 的任何 configure 版本(通常是 svelte.config.js)中添加 experimental.async 选项来选择加入:

¥This feature is currently experimental, and you must opt in by adding the experimental.async option wherever you configure Svelte, usually svelte.config.js:

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

实验性标志将在 Svelte 6 中被移除。

¥The experimental flag will be removed in Svelte 6.

边界(Boundaries)

¥Boundaries

目前,你只能在 <svelte:boundary> 中使用 await 并附带 pending 代码片段:

¥Currently, you can only use await inside a <svelte:boundary> with a pending snippet:

<svelte:boundary>
	<MyApp />

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

一旦 Svelte 支持异步服务器端渲染(参见 caveats),此限制将被解除。

¥This restriction will be lifted once Svelte supports asynchronous server-side rendering (see caveats).

playground 中,你的应用会在一个带有空的待处理代码片段的边界内渲染,因此你无需创建 await 代码片段即可使用 await

同步更新(Synchronized updates)

¥Synchronized updates

await 表达式依赖于特定状态时,对该状态的更改将直到异步工作完成才会反映在 UI 中,这样 UI 就不会处于不一致的状态。换句话说,在像 this 这样的例子中……

¥When an await expression depends on a particular piece of state, changes to that state will not be reflected in the UI until the asynchronous work has completed, so that the UI is not left in an inconsistent state. In other words, in an example like this...

<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> 的内容不会立即更新以读取此值——

¥...if you increment a, the contents of the <p> will not immediately update to read this —

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

— 相反,当 add(a, b) 解析时,文本将更新为 2 + 2 = 4

¥— instead, the text will update to 2 + 2 = 4 when add(a, b) resolves.

更新可以重叠 - 快速更新将反映在 UI 中,而之前的慢速更新仍在进行中。

¥Updates can overlap — a fast update will be reflected in the UI while an earlier slow update is still ongoing.

并发性(Concurrency)

¥Concurrency

Svelte 将尽可能多地并行执行异步工作。例如,如果你的标记中有两个 await 表达式……

¥Svelte will do as much asynchronous work as it can in parallel. For example if you have two await expressions in your markup...

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

...这两个函数将同时运行,因为它们是独立的表达式,即使它们在视觉上是连续的。

¥...both functions will run at the same time, as they are independent expressions, even though they are visually sequential.

这不适用于 <script> 内部或异步函数内部的顺序 await 表达式 - 这些表达式的运行方式与其他异步 JavaScript 一样。一个例外是,独立的 $derived 表达式将独立更新,即使它们在首次创建时会按顺序运行:

¥This does not apply to sequential await expressions inside your <script> or inside async functions — these run like any other asynchronous JavaScript. An exception is that independent $derived expressions will update independently, even though they will run sequentially when they are first created:

// these will run sequentially the first time,
// but will update independently
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 警告。

加载状态指示(Indicating loading states)

¥Indicating loading states

除了最近边界的 pending 代码片段外,你还可以使用 $effect.pending() 指示异步工作正在进行中。

¥In addition to the nearest boundary’s pending snippet, you can indicate that asynchronous work is ongoing with $effect.pending().

你还可以使用 settled() 获取在当前更新完成时解析的 Promise:

¥You can also use settled() to get a promise that resolves when the current update is complete:

import { function tick(): Promise<void>

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

tick
, import settledsettled } from 'svelte';
async function function onclick(): Promise<void>onclick() { let updating: booleanupdating = true; // without this, the change to `updating` will be // grouped with the other changes, meaning it // won't be reflected in the 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 import settledsettled(); // any updates affected by `color` or `answer` // have now been applied let updating: booleanupdating = false; }

错误处理(Error handling)

¥Error handling

await 表达式中的错误会冒泡到最近的 错误边界

¥Errors in await expressions will bubble to the nearest error boundary.

注意事项(Caveats)

¥Caveats

作为一项实验性功能,await 的处理方式(以及与 $effect.pending() 类似的相关 API)的细节可能会在 semver 主要版本之外发生重大变更,但我们打算将此类变更保持在最低限度。

¥As an experimental feature, the details of how await is handled (and related APIs like $effect.pending()) are subject to breaking changes outside of a semver major release, though we intend to keep such changes to a bare minimum.

目前,服务器端渲染是同步的。如果在 SSR 期间遇到带有 pending 代码片段的 <svelte:boundary>,则只会渲染 pending 代码片段。

¥Currently, server-side rendering is synchronous. If a <svelte:boundary> with a pending snippet is encountered during SSR, only the pending snippet will be rendered.

重大变更(Breaking changes)

¥Breaking changes

experimental.async 选项为 true 时,Effect 的运行顺序会略有不同。具体来说,现在在同一组件中,像 {#if ...}{#each ...} 这样的块 effect 会在 $effect.prebeforeUpdate 之前运行,这意味着在 非常罕见的情况 中,可以更新一个本不该存在的块,但前提是你必须在 effect 中更新状态(你应该避免的情况)。

¥Effects run in a slightly different order when the experimental.async option is true. Specifically, block effects like {#if ...} and {#each ...} now run before an $effect.pre or beforeUpdate in the same component, which means that in very rare situations it is possible to update a block that should no longer exist, but only if you update state inside an effect, which you should avoid.

上一页 下一页