SvelteKit为何在SSR时跳过会引发ReferenceError的代码块?
SvelteKit中{#await}块为何能跳过服务端错误代码?
默认情况下SvelteKit会先执行SSR(服务端渲染)再执行CSR(客户端渲染),因此在服务端直接访问window对象时,会触发ReferenceError错误。
代码示例1:直接调用异步函数(服务端报错)
<script lang="ts"> import { browser } from "$app/environment"; async function hello_world() { console.log(`hello world from: ${browser ? "client" : "server"}`); console.log(window.localStorage); console.log("after accessing localStorage"); } hello_world(); </script> <p>Hello World!</p>
执行报错:
ReferenceError: window is not defined
代码示例2:用{#await}块调用异步函数(服务端无报错)
<script lang="ts"> import { browser } from "$app/environment"; async function hello_world() { console.log(`hello world from: ${browser ? "client" : "server"}`); console.log(window.localStorage); console.log("after accessing localStorage"); } </script> {#await hello_world()} <p>Hello World!</p> {/await}
客户端输出:
hello world from: client <Storage object> after accessing localStorage
服务端输出:
hello world from: server
原因解析
SSR的异步处理逻辑:
在SSR阶段,SvelteKit会识别{#await}块中的异步函数调用,不会在服务端完整执行整个函数。当函数内部抛出未捕获的Promise拒绝(这里访问window的同步错误会被自动包装成拒绝的Promise),SvelteKit会终止该函数在服务端的执行,不会继续执行后续代码行,也不会抛出错误中断SSR流程。错误的隐式捕获:
异步函数中同步抛出的错误会自动转为Promise的拒绝状态。{#await}块在服务端会处理这个拒绝:它不会让错误冒泡扩散,仅渲染等待状态的内容;等到客户端CSR阶段,函数会重新执行,此时window对象存在,就能正常完成所有代码逻辑。直接调用与{#await}的核心差异:
代码示例1中直接调用hello_world()时,函数在服务端同步执行,访问window的错误是同步抛出且无任何Promise捕获,因此直接触发ReferenceError中断SSR;而示例2中{#await}块会将函数调用包装进Promise处理逻辑,同步错误被转为Promise拒绝后,SvelteKit的SSR渲染器会处理这个拒绝,避免错误扩散。
内容的提问来源于stack exchange,提问作者Tirafesi
相关产品推荐
相关产品推荐

