SvelteKit项目中如何等待子组件完成后调用函数?
SvelteKit 认证函数调用顺序问题解决
问题场景
在SvelteKit项目中,两个组件共享根布局,需调用根布局定义的两个函数:
IamAuth:耗时5秒的认证初始化操作GetIsLoggedIn:耗时1秒的登录状态查询,但必须在IamAuth执行完成后调用,否则会报错
当前NavBar组件的onMount钩子中调用IamAuth可正常执行,但另一个布局组件的onMount中调用GetIsLoggedIn时,因IamAuth未完成而报错,需要实现等待IamAuth执行完毕后再调用GetIsLoggedIn的逻辑。
现有代码示例
根布局组件(+Layout.svelte)
<script> import { setContext } from 'svelte'; const IamAuth = () => { // 模拟5秒耗时操作,需先于GetIsLoggedIn执行 } const GetIsLoggedIn = () => { // 模拟1秒耗时操作,若先于IamAuth调用会报错 } setContext('authContext', { IamAuth, GetIsLoggedIn, }); </script> <slot />
NavBar组件(NavBar.svelte)
<script> import { onMount, getContext } from 'svelte'; const { IamAuth } = getContext('authContext'); onMount(() => { IamAuth(); // 执行正常 }); </script> <nav>导航栏内容</nav>
另一个布局组件(+Layout.svelte)
<script> import { onMount, getContext } from 'svelte'; import NavBar from '$lib/components/NavBar.svelte'; const { GetIsLoggedIn } = getContext('authContext'); onMount(() => { GetIsLoggedIn(); // 执行报错,因为IamAuth尚未完成 }); </script> <NavBar /> <slot />
解决方案
方案1:在根布局中封装函数,强制调用顺序
修改根布局,用Promise跟踪IamAuth的执行状态,让GetIsLoggedIn自动等待IamAuth完成:
<!-- 根 +Layout.svelte --> <script> import { setContext } from 'svelte'; // 用Promise存储IamAuth的执行状态 let authPromise = null; const IamAuth = async () => { if (authPromise) return authPromise; // 模拟5秒耗时操作 authPromise = new Promise(resolve => { setTimeout(() => { console.log('IamAuth 执行完成'); resolve(); }, 5000); }); return authPromise; }; const GetIsLoggedIn = async () => { // 等待IamAuth完成后再执行自身逻辑 await authPromise; // 模拟1秒耗时操作 return new Promise(resolve => { setTimeout(() => { console.log('GetIsLoggedIn 执行完成'); resolve(true); // 返回实际登录状态 }, 1000); }); }; setContext('authContext', { IamAuth, GetIsLoggedIn, }); </script> <slot />
修改后组件无需额外改动:
- NavBar组件调用
IamAuth时会初始化并返回Promise - 另一个布局组件调用
GetIsLoggedIn时,会自动等待authPromise完成后再执行逻辑
方案2:通过上下文传递认证完成Promise
如果不想修改GetIsLoggedIn内部逻辑,可在根布局中单独暴露等待认证完成的方法:
<!-- 根 +Layout.svelte --> <script> import { setContext } from 'svelte'; const IamAuth = async () => { // 模拟5秒耗时操作 return new Promise(resolve => { setTimeout(() => { console.log('IamAuth 执行完成'); resolve(); }, 5000); }); }; let authPromise = null; setContext('authContext', { IamAuth: async () => { // 确保IamAuth只执行一次 if (!authPromise) authPromise = IamAuth(); return authPromise; }, GetIsLoggedIn: async () => { // 模拟1秒耗时操作 return new Promise(resolve => { setTimeout(() => { console.log('GetIsLoggedIn 执行完成'); resolve(true); }, 1000); }); }, // 暴露等待认证完成的方法 waitForAuth: () => authPromise }); </script> <slot />
在另一个布局组件中主动等待:
<!-- 另一个 +Layout.svelte --> <script> import { onMount, getContext } from 'svelte'; import NavBar from '$lib/components/NavBar.svelte'; const { GetIsLoggedIn, waitForAuth } = getContext('authContext'); onMount(async () => { // 先等待IamAuth完成 await waitForAuth(); // 再调用GetIsLoggedIn const isLoggedIn = await GetIsLoggedIn(); console.log('当前登录状态:', isLoggedIn); }); </script> <NavBar /> <slot />
方案3:使用Svelte存储跟踪认证状态
通过Svelte的writable和derived存储,全局跟踪认证完成状态,让组件订阅等待:
<!-- 根 +Layout.svelte --> <script> import { setContext, writable, derived } from 'svelte'; // 跟踪认证是否完成 const isAuthCompleted = writable(false); const IamAuth = async () => { // 模拟5秒耗时操作 await new Promise(resolve => setTimeout(resolve, 5000)); isAuthCompleted.set(true); console.log('IamAuth 执行完成'); }; const GetIsLoggedIn = async () => { // 模拟1秒耗时操作 await new Promise(resolve => setTimeout(resolve, 1000)); console.log('GetIsLoggedIn 执行完成'); return true; }; // 创建派生存储,等待认证完成 const authReady = derived(isAuthCompleted, $completed => $completed); setContext('authContext', { IamAuth, GetIsLoggedIn, authReady }); </script> <slot />
在另一个布局组件中订阅authReady:
<!-- 另一个 +Layout.svelte --> <script> import { onMount, getContext } from 'svelte'; import NavBar from '$lib/components/NavBar.svelte'; const { GetIsLoggedIn, authReady } = getContext('authContext'); onMount(async () => { // 等待认证完成 await authReady; const isLoggedIn = await GetIsLoggedIn(); console.log('当前登录状态:', isLoggedIn); }); </script> <NavBar /> <slot />
内容的提问来源于stack exchange,提问作者Rodrigo Santamaria
相关产品推荐
相关产品推荐

