You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SvelteKit{#await}加载状态预览模式失效及Safari兼容问题求助

在SvelteKit中使用{#await}实现加载状态的问题解决

问题描述

刚开始学Svelte,想用{#await}指令模拟服务器数据加载状态,预期页面先显示“Loading data...”,5秒后显示“Hello World”,但实际出现以下问题:

  • 执行npm run preview时,浏览器要等Promise完成才渲染页面;
  • npm run dev模式下只有Chrome能正常显示加载状态,Safari不管哪种模式都不行;
  • 两种模式下console.log(data.message)都显示服务器返回的是Promise。
    当前使用SvelteKit 2.22。

代码示例

+page.svelte

<script lang="ts">
    import type { PageData } from './$types';
    let { data }: { data: PageData } = $props();
    console.log(data.message);
</script>

<h1>Await Test</h1>

{#await data.message}
    <p>Loading data...</p>
{:then result}
    <p>{result}</p>
{:catch error}
    <p>Error: {error.message}</p>
{/await}

+page.server.ts

import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async () => {
    const promise = new Promise<string>(async (resolve) => {
        await new Promise((r) => setTimeout(r, 5000));
        resolve('Hello World');
    });

    return {
        message: promise
    };
};

问题原因

SvelteKit在生产构建(preview对应生产产物)时,会自动解析load函数返回的Promise,等它完成后再把数据传给客户端——这是为了优化首屏渲染的SEO和性能,避免客户端再等异步数据。而开发模式为了调试方便,会保留Promise传递,让客户端处理异步状态。Safari的表现差异则是因为它对Promise序列化的处理和Chrome不同。

正确实现方式

要在客户端显示加载状态,得在客户端发起异步请求,不能在服务器load函数里返回未解析的Promise,以下两种方法都可行:

方法1:组件内发起异步请求

修改服务器load函数返回占位数据,组件挂载后再发起异步请求:

// +page.server.ts
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async () => {
    return {
        message: null // 返回占位值
    };
};
<!-- +page.svelte -->
<script lang="ts">
    import type { PageData } from './$types';
    import { onMount } from 'svelte';
    let { data }: { data: PageData } = $props();
    let messagePromise: Promise<string> | null = null;

    onMount(() => {
        // 客户端模拟异步请求延迟
        messagePromise = new Promise<string>((resolve) => {
            setTimeout(() => {
                resolve('Hello World');
            }, 5000);
        });
    });
</script>

<h1>Await Test</h1>

{#await messagePromise}
    <p>Loading data...</p>
{:then result}
    <p>{result}</p>
{:catch error}
    <p>Error: {error.message}</p>
{/await}

方法2:调用API路由获取数据

先创建API端点处理异步逻辑,再在组件内请求这个API:

// +server.ts(API端点)
import type { RequestHandler } from './$types';

export const GET: RequestHandler = async () => {
    await new Promise((r) => setTimeout(r, 5000));
    return new Response(JSON.stringify({ message: 'Hello World' }), {
        headers: { 'Content-Type': 'application/json' }
    });
};
<!-- +page.svelte -->
<script lang="ts">
    import { onMount } from 'svelte';
    let messagePromise: Promise<string> | null = null;

    onMount(async () => {
        messagePromise = (async () => {
            const res = await fetch('/'); // 对应上面的+server.ts路由
            const data = await res.json();
            return data.message;
        })();
    });
</script>

<h1>Await Test</h1>

{#await messagePromise}
    <p>Loading data...</p>
{:then result}
    <p>{result}</p>
{:catch error}
    <p>Error: {error.message}</p>
{/await}

额外提示

  • 生产模式下SvelteKit自动解析load里的Promise是默认优化,不要强行绕过,否则会影响首屏性能和SEO;
  • 如果需要服务器端加载数据但又想显示加载状态,可以考虑用SvelteKit的懒加载组件或者路由级别的加载状态,但上面的两种方法更直接。

内容的提问来源于stack exchange,提问作者user31393851

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 10:53:12