首页 / Svelte 5 入门教程 / {#key} 与 {#await} 块

Svelte 5 入门教程

{#key} 与 {#await} 块

本教程共 50 篇 · 第 14 篇 · 更新于 2026-08-05 · 约 5 分钟阅读

SvelteSvelte 5模板语法{#key}{#await}异步

14. {#key} 与 {#await} 块

本节目标:掌握 {#key} 块的重建机制和 {#await} 块的异步渲染模式。学完你能在值变化时重置组件状态,并优雅地处理 Promise 的三种状态。

{#key} 块

基本语法

{#key} 块在表达式的值变化时,销毁并重新创建其内部内容:

<script>
	let userId = $state(1);

	function switchUser() {
		userId = userId === 1 ? 2 : 1;
	}
</script>

{#key userId}
	<UserProfile {userId} />
{/key}

<button onclick={switchUser}>切换用户</button>

每次点击切换按钮时,userId 变化,{#key} 块内部的 <UserProfile> 组件会被销毁并重新创建。

为什么需要 {#key}

打个比方,{#key} 就像换频道——你切换到新频道时,旧频道的画面完全消失,新频道从头开始播放。

有些场景下你需要这种行为:

场景一:重置组件状态

{#key currentTab}
	<TabContent tab={currentTab} />
{/key}

切换标签页时,旧标签的组件状态(如表单输入)被清空,新标签从头开始。

场景二:重新触发过渡动画

<script>
	import { fade } from 'svelte/transition';

	let value = $state(0);
</script>

{#key value}
	<div transition:fade>
		当前值:{value}
	</div>
{/key}

<button onclick={() => value++}>下一个</button>

每次 value 变化时,旧 <div> 淡出,新 <div> 淡入,产生连续的动画效果。

场景三:重新执行组件初始化逻辑

{#key projectId}
	<ProjectDashboard {projectId} />
{/key}

切换项目时,ProjectDashboard 重新初始化,重新加载数据。

Note

{#key}{#each} 中的 key 是不同概念。{#each (key) 用于列表项追踪,{#key} 块用于值变化时重建内容。

{#await} 块

基本语法

{#await} 块处理 Promise 的三种状态:等待中(pending)、已完成(fulfilled)、已拒绝(rejected)。

<script>
	let promise = fetch('/api/data').then(r => r.json());
</script>

{#await promise}
	<!-- pending: 等待中 -->
	<p>加载中...</p>
{:then data}
	<!-- fulfilled: 已完成 -->
	<p>数据:{data.name}</p>
{:catch error}
	<!-- rejected: 已拒绝 -->
	<p>出错了:{error.message}</p>
{/await}

三种简写形式

省略 catch:不需要处理错误时:

{#await promise}
	<p>加载中...</p>
{:then data}
	<p>数据:{data.name}</p>
{/await}

省略 pending:不关心加载状态时:

{#await promise then data}
	<p>数据:{data.name}</p>
{/await}

只处理错误:只关心错误时:

{#await promise catch error}
	<p>出错了:{error}</p>
{/await}

实用示例:异步获取随机用户

<script>
	let promise = $state();

	async function getRandomUser() {
		const res = await fetch('https://randomuser.me/api/');
		const data = await res.json();
		return data.results[0];
	}

	function loadUser() {
		promise = getRandomUser();
	}

	loadUser(); // 初始加载
</script>

{#await promise}
	<p>正在加载用户信息...</p>
{:then user}
	<div>
		<img src={user.picture.medium} alt="头像" />
		<p>{user.name.first} {user.name.last}</p>
		<p>{user.email}</p>
	</div>
{:catch error}
	<p>加载失败:{error.message}</p>
{/await}

<button onclick={loadUser}>换一个</button>

动态更新 Promise

{#await}$state 结合,可以实现「重新请求」:

<script>
	let userId = $state(1);
	let userPromise = $derived(fetchUser(userId));

	async function fetchUser(id) {
		const res = await fetch(`/api/users/${id}`);
		if (!res.ok) throw new Error('用户不存在');
		return res.json();
	}
</script>

<input type="number" bind:value={userId} min="1" />

{#await userPromise}
	<p>加载中...</p>
{:then user}
	<h3>{user.name}</h3>
	<p>{user.email}</p>
{:catch error}
	<p>错误:{error.message}</p>
{/await}

userId 变化时,userPromise 通过 $derived 自动更新,{#await} 自动处理新的 Promise。

Tip

在 SvelteKit 中,数据获取通常通过 load 函数处理,不需要手动写 {#await}。但了解 {#await} 对理解异步渲染很重要。

SSR 中的行为

在服务端渲染时,{#await} 只会渲染 pending 分支。Promise 在服务端不会等待完成。

Note

如果表达式不是 Promise(比如普通值),会直接进入 :then 分支,包括 SSR 时。

懒加载组件

{#await} 可以配合动态 import() 实现组件懒加载:

{#await import('./HeavyComponent.svelte') then { default: Component }}
	<Component />
{/await}

HeavyComponent 只在需要时才加载,减少首屏代码体积。

本节回顾

  • {#key 表达式} 在值变化时销毁并重建内部内容
  • {#key} 适用场景:重置组件状态、重新触发动画、重新初始化
  • {#await Promise} 处理异步三种状态:pending / then / catch
  • 三种简写:省略 catch、省略 pending、只保留 catch
  • 配合 $derived 可以实现 Promise 自动更新
  • SSR 时只渲染 pending 分支
  • 配合 import() 可实现组件懒加载