{#key} 与 {#await} 块
本教程共 50 篇 · 第 14 篇 · 更新于 2026-08-05 · 约 5 分钟阅读
本节目标:掌握 {#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()可实现组件懒加载