<svelte:boundary> 错误边界
本教程共 50 篇 · 第 29 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
29. svelte:boundary 错误边界
本节目标:学会用 svelte:boundary 隔离错误,掌握 failed 和 pending snippet 的用法,理解错误恢复机制和 onerror 回调。
什么是错误边界
组件渲染时可能抛出错误——访问了 undefined 的属性、数据格式不对等等。如果没有错误边界,一个小组件的崩溃会让整个页面白屏。
错误边界就像给组件装了”防火墙”——里面的组件崩了,外面不受影响,还能显示一个友好的提示界面。
打个比方,错误边界就像大楼里的防火门。某个房间着火了,防火门自动关闭,火势不会蔓延到其他房间。
<svelte:boundary> 是 Svelte 5.3.0 新增的功能。
基本用法
错误边界需要配合 failed snippet 使用。当内部组件出错时,failed snippet 会替代原来的内容显示。
<script>
import FlakyComponent from './FlakyComponent.svelte';
</script>
<svelte:boundary>
<FlakyComponent />
{#snippet failed(error, reset)}
<div style="padding: 20px; background: #fee; border: 1px solid #f00;">
<p>出错了:{error.message}</p>
<button onclick={reset}>重试</button>
</div>
{/snippet}
</svelte:boundary>
failed snippet 接收两个参数:
error:抛出的错误对象reset:一个函数,调用后会重新渲染边界内的内容
Note错误边界只会捕获渲染过程和 effect 执行时的错误。事件处理器里、
setTimeout回调里、异步操作后的错误不会被捕获——这些需要你用try/catch自己处理。
pending snippet
pending snippet 在边界首次创建时显示,直到内部的所有 await 表达式都解析完毕。
<script>
async function delayed(data) {
await new Promise(r => setTimeout(r, 1000));
return data;
}
</script>
<svelte:boundary>
<p>{await delayed('hello!')}</p>
{#snippet pending()}
<p>加载中...</p>
{/snippet}
</svelte:boundary>
页面打开时先显示”加载中…”,一秒后变成”hello!”。
Note
pendingsnippet 只在边界首次创建时显示,后续的异步更新不会触发。如果你需要追踪后续的异步状态,可以用$effect.pending()。
onerror 回调
除了 failed snippet,你还可以提供 onerror 回调函数。它接收同样的 error 和 reset 参数,但不会替代内容显示——适合用来上报错误。
<script>
function reportError(error) {
// 把错误发送到错误监控服务
fetch('/api/errors', {
method: 'POST',
body: JSON.stringify({ message: error.message, stack: error.stack })
});
}
</script>
<svelte:boundary onerror={(error) => reportError(error)}>
<FlakyComponent />
{#snippet failed(error, reset)}
<p>出了点问题,工程师正在抢修</p>
<button onclick={reset}>重试</button>
{/snippet}
</svelte:boundary>
在外部处理错误
有时候你想在边界外面控制错误状态。可以把 error 和 reset 存到状态变量中。
<script>
let error = $state(null);
let resetFn = $state(() => {});
function onerror(e, reset) {
error = e;
resetFn = reset;
}
</script>
<svelte:boundary {onerror}>
<FlakyComponent />
</svelte:boundary>
{#if error}
<div>
<p>错误:{error.message}</p>
<button onclick={() => {
error = null;
resetFn();
}}>
重试
</button>
</div>
{/if}
错误恢复
reset 函数是错误恢复的关键。调用它会重新渲染边界内的所有内容。
<script>
let data = $state({ value: 42 });
let renderCount = $state(0);
function breakIt() {
// 故意制造错误
data = undefined;
}
</script>
<svelte:boundary>
<button onclick={breakIt}>制造错误</button>
<!-- 访问 undefined 的 value 属性会抛错 -->
<p>值:{data.value}</p>
{#snippet failed(error, reset)}
<div>
<p>崩溃了!{error.message}</p>
<button onclick={() => {
// 修复数据后重置
data = { value: 0 };
reset();
}}>
修复并重试
</button>
</div>
{/snippet}
</svelte:boundary>
Tip
reset只是重新渲染组件。如果导致错误的数据没有被修复,重试后还是会报错。调用reset前先修复数据源。
嵌套错误边界
错误边界可以嵌套。内部的边界捕获错误后,外部边界不会收到这个错误。如果内部边界没有 failed snippet 或 onerror,错误会冒泡到外部边界。
<svelte:boundary>
<!-- 外层错误边界 -->
<p>外层内容</p>
<svelte:boundary>
<!-- 内层错误边界 -->
<FlakyComponent />
{#snippet failed(error, reset)}
<p>内层捕获:{error.message}</p>
<button onclick={reset}>内层重试</button>
{/snippet}
</svelte:boundary>
{#snippet failed(error, reset)}
<p>外层捕获:{error.message}</p>
<button onclick={reset}>外层重试</button>
{/snippet}
</svelte:boundary>
Note如果
onerror函数内部抛出错误(或重新抛出原始错误),这个错误会被父级错误边界处理。
实战:带加载和错误的异步组件
<script>
let userId = $state(1);
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error('用户不存在');
return res.json();
}
</script>
<svelte:boundary>
<div>
<button onclick={() => userId += 1}>下一个用户</button>
<div>
<h3>用户信息</h3>
<p>姓名:{(await fetchUser(userId)).name}</p>
</div>
</div>
{#snippet pending()}
<p>正在加载用户数据...</p>
{/snippet}
{#snippet failed(error, reset)}
<div style="color: red;">
<p>加载失败:{error.message}</p>
<button onclick={reset}>重试</button>
</div>
{/snippet}
</svelte:boundary>
本节回顾
<svelte:boundary>是 Svelte 5 的错误边界,隔离组件崩溃,防止整页白屏failedsnippet 在出错时显示,接收error和reset两个参数pendingsnippet 在首次加载时显示,直到await表达式解析完毕onerror回调用于错误上报,不会替代内容显示reset()重新渲染边界内容,但需要先修复导致错误的数据- 错误边界可以嵌套,未处理的错误会冒泡到父级边界
- 事件处理器和异步回调中的错误不会被边界捕获